Compare commits
131 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63c3690fa8 | ||
|
|
e2ece2c35b | ||
|
|
86d6e96f7a | ||
|
|
87e1ccc6bf | ||
|
|
aa355e22f9 | ||
|
|
d21f758158 | ||
|
|
f2741116a7 | ||
|
|
ea92bf7718 | ||
|
|
e2bbbd7835 | ||
|
|
b38ae3aad3 | ||
|
|
68d8b35ab8 | ||
|
|
5d25b0ae9b | ||
|
|
8fa4df0076 | ||
|
|
909d5ec139 | ||
|
|
64a0bf67db | ||
|
|
a9047947b0 | ||
|
|
d49adfdef3 | ||
|
|
498b665c8a | ||
|
|
14c3824632 | ||
|
|
eb93af3622 | ||
|
|
b7691afb8d | ||
|
|
61c61c8844 | ||
|
|
120207f1f9 | ||
|
|
ceb6a44238 | ||
|
|
6a1b2f0610 | ||
|
|
95d4d90efd | ||
|
|
6605a1c3c2 | ||
|
|
0c754affd9 | ||
|
|
1e45abe988 | ||
|
|
6852e25372 | ||
|
|
ac8256a96b | ||
|
|
0786016436 | ||
|
|
f67b5db2f9 | ||
|
|
949fbdba14 | ||
|
|
558ffee93b | ||
|
|
69274ed7f9 | ||
|
|
7f7d0a0aa2 | ||
|
|
683d49bc71 | ||
|
|
da77f89910 | ||
|
|
9b9310dc84 | ||
|
|
1f94752e12 | ||
|
|
016958cb41 | ||
|
|
b003a2b1e3 | ||
|
|
eef665c896 | ||
|
|
e7492047c0 | ||
|
|
71db6de14f | ||
|
|
246048d8be | ||
|
|
3a7fb0971b | ||
|
|
b672357f78 | ||
|
|
302d8ec3b2 | ||
|
|
cdbf8d6fc5 | ||
|
|
f5f9d4983f | ||
|
|
2d67984536 | ||
|
|
e042bc3a17 | ||
|
|
297e2a13a2 | ||
|
|
4df8f475ce | ||
|
|
638264d874 | ||
|
|
21785a1a08 | ||
|
|
8e50c20c9d | ||
|
|
c5d2ddc156 | ||
|
|
e9adb18d58 | ||
|
|
146408655b | ||
|
|
3b7d583d8f | ||
|
|
4a704dde0c | ||
|
|
f5f8423364 | ||
|
|
00a5f72857 | ||
|
|
f4ec61340f | ||
|
|
a46d22b31f | ||
|
|
7ad8bbe6e7 | ||
|
|
fcbdd00bce | ||
|
|
491a56db10 | ||
|
|
cbe31981b3 | ||
|
|
dafe9824e3 | ||
|
|
b931066573 | ||
|
|
f45e107207 | ||
|
|
ece3bc4d85 | ||
|
|
4b9ee685ac | ||
|
|
cfc43685a4 | ||
|
|
d05d5f594b | ||
|
|
425036adc9 | ||
|
|
cb174592be | ||
|
|
7a350a5e83 | ||
|
|
afadf3ea3f | ||
|
|
c8ccf053ff | ||
|
|
2f74250634 | ||
|
|
ad7faaab81 | ||
|
|
e39a841f6e | ||
|
|
fc7c6afa81 | ||
|
|
51bc9d1569 | ||
|
|
747bbd7c7b | ||
|
|
521ffbfaaf | ||
|
|
cd33e5b274 | ||
|
|
201ea843a0 | ||
|
|
dee210ceec | ||
|
|
ea0e52c5a2 | ||
|
|
b5578ff5bc | ||
|
|
f9ad3cb029 | ||
|
|
30c24c59ed | ||
|
|
6f05c9d327 | ||
|
|
30429b88b3 | ||
|
|
394be61a65 | ||
|
|
d55f6d7baa | ||
|
|
2dfcab170d | ||
|
|
59b2094ad1 | ||
|
|
8046600a55 | ||
|
|
17a655b52a | ||
|
|
75b8587216 | ||
|
|
7c87ab88bc | ||
|
|
b87470a284 | ||
|
|
948bf10bad | ||
|
|
59c3761455 | ||
|
|
b50f5ecf3e | ||
|
|
be9c492406 | ||
|
|
85e1a356fe | ||
|
|
5da4c1653a | ||
|
|
64edd55add | ||
|
|
bd28ee77d9 | ||
|
|
d10a505aa9 | ||
|
|
77f744eba4 | ||
|
|
f8dde00a33 | ||
|
|
380f260027 | ||
|
|
6df4eb4bee | ||
|
|
18fcc4952d | ||
|
|
3878bd6a49 | ||
|
|
067234e9fb | ||
|
|
e32d2342a6 | ||
|
|
82776df9d6 | ||
|
|
f351b6fd8e | ||
|
|
a7e4cf42e2 | ||
|
|
a4542e907e | ||
|
|
12e3fd64bb |
2
AUTHORS
2
AUTHORS
@@ -29,6 +29,8 @@ Contributors:
|
||||
Oskari Rauta : separator plugin, gradients
|
||||
Michael Messmore : Support for Path in .desktop files
|
||||
Matthew Otnel : config option systray_name_filter
|
||||
Ryan Gray, Jeff Blake (https://gitlab.com/berkley4) : battery format
|
||||
aaaz (https://gitlab.com/aaaz) : clock fixes
|
||||
|
||||
Translations:
|
||||
Bosnian:
|
||||
|
||||
@@ -6,6 +6,7 @@ option( ENABLE_TINT2CONF "Enable tint2conf build, a GTK+2 theme configurator for
|
||||
option( ENABLE_EXTRA_THEMES "Install additional tint2 themes" ON )
|
||||
option( ENABLE_RSVG "Rsvg support (launcher only)" ON )
|
||||
option( ENABLE_SN "Startup notification support" ON )
|
||||
option( ENABLE_TRACING "Build tint2 with tracing instrumentation" OFF )
|
||||
option( ENABLE_ASAN "Build tint2 with AddressSanitizer" OFF )
|
||||
option( ENABLE_BACKTRACE "Dump a backtrace in case of fatal errors (e.g. X11 I/O error)" OFF )
|
||||
option( ENABLE_BACKTRACE_ON_SIGNAL "Dump a backtrace also when receiving signals such as SIGSEGV" OFF )
|
||||
@@ -83,10 +84,10 @@ if( NOT IMLIB_BUILD_WITH_X )
|
||||
endif( NOT IMLIB_BUILD_WITH_X )
|
||||
|
||||
|
||||
add_definitions( -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_WITH_GETLINE )
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_definitions( -D_POSIX_C_SOURCE=200809L -D_BSD_SOURCE -D_DEFAULT_SOURCE )
|
||||
else(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_definitions( -D_WITH_GETLINE )
|
||||
add_definitions( -D_POSIX_C_SOURCE=200809L )
|
||||
endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
||||
|
||||
@@ -116,7 +117,12 @@ include_directories( ${PROJECT_BINARY_DIR}
|
||||
set( SOURCES src/config.c
|
||||
src/panel.c
|
||||
src/server.c
|
||||
src/tint.c
|
||||
src/main.c
|
||||
src/init.c
|
||||
src/signals.c
|
||||
src/tracing.c
|
||||
src/mouse_actions.c
|
||||
src/drag_and_drop.c
|
||||
src/clock/clock.c
|
||||
src/systray/systraybar.c
|
||||
src/launcher/launcher.c
|
||||
@@ -135,11 +141,13 @@ set( SOURCES src/config.c
|
||||
src/tint2rc.c
|
||||
src/util/area.c
|
||||
src/util/common.c
|
||||
src/util/fps_distribution.c
|
||||
src/util/strnatcmp.c
|
||||
src/util/timer.c
|
||||
src/util/cache.c
|
||||
src/util/color.c
|
||||
src/util/gradient.c
|
||||
src/util/uevent.c
|
||||
src/util/window.c )
|
||||
|
||||
if( ENABLE_BATTERY )
|
||||
@@ -210,14 +218,23 @@ if( ENABLE_TINT2CONF )
|
||||
endif( ENABLE_TINT2CONF )
|
||||
|
||||
if( ENABLE_ASAN )
|
||||
SET(ASAN_C_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow")
|
||||
SET(ASAN_L_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold ")
|
||||
SET(ASAN_C_FLAGS " -O0 -g3 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow")
|
||||
SET(ASAN_L_FLAGS " -O0 -g3 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold ")
|
||||
else()
|
||||
SET(ASAN_C_FLAGS "")
|
||||
SET(ASAN_L_FLAGS "")
|
||||
endif()
|
||||
|
||||
add_custom_target( version ALL "${PROJECT_SOURCE_DIR}/get_version.sh" "\"${PROJECT_SOURCE_DIR}\"" )
|
||||
if( ENABLE_TRACING )
|
||||
add_definitions( -DHAVE_TRACING )
|
||||
SET(TRACING_C_FLAGS " -finstrument-functions -finstrument-functions-exclude-file-list=tracing.c -finstrument-functions-exclude-function-list=get_time,gettime -O0 -g3 -fno-common -fno-omit-frame-pointer -rdynamic")
|
||||
SET(TRACING_L_FLAGS " -O0 -g3 -fno-common -fno-omit-frame-pointer -rdynamic")
|
||||
else()
|
||||
SET(TRACING_C_FLAGS "")
|
||||
SET(TRACING_L_FLAGS "")
|
||||
endif()
|
||||
|
||||
add_custom_target( version ALL "${PROJECT_SOURCE_DIR}/get_version.sh" -- "\"${PROJECT_SOURCE_DIR}/\"" )
|
||||
|
||||
link_directories( ${X11_LIBRARY_DIRS}
|
||||
${PANGOCAIRO_LIBRARY_DIRS}
|
||||
@@ -251,8 +268,8 @@ 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}" )
|
||||
set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS}" )
|
||||
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 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 )
|
||||
|
||||
70
ChangeLog
70
ChangeLog
@@ -1,4 +1,70 @@
|
||||
2017-04-23 0.14.2
|
||||
2017-09-08 15.1
|
||||
- Fixes:
|
||||
- Fixed build on non-Linux and non-x86 systems
|
||||
|
||||
2017-09-02 15.0
|
||||
- Fixes:
|
||||
- Clock, executors and other timers fire correctly after waking up from suspend
|
||||
- One-shot timers are restarted correctly from their own callbacks
|
||||
- Clock is refreshed with better accuracy (thanks @aaaz)
|
||||
- Panel: by popular demand, the old struts behavior with autohide has been restored (issue #619);
|
||||
if you encounter applications that interact poorly with it,
|
||||
you might have better luck with strut_policy = minimum,
|
||||
if that does not work, you will have to turn off autohide.
|
||||
- Enhancements:
|
||||
- Panel:
|
||||
- _NET_WM_PID is set correctly, so now tint2 can be interacted with more easily from wmctrl and similar apps
|
||||
- Taskbar: new config option taskbar_hide_different_desktop
|
||||
- Battery:
|
||||
- New config option bat1_format and bat2_format
|
||||
- New config option battery_full_cmd
|
||||
- Better "Unknown" state handling
|
||||
- Executor:
|
||||
- Hide if output is empty
|
||||
- If no user tooltip is set, displays the script standard error as tooltip.
|
||||
Tooltip is multiline, can be cleared with the VT100 clear screen sequence, in shell: (>&2 echo -en "\033[2J").
|
||||
Long tooltips are truncated to 4096 characters.
|
||||
- Launcher:
|
||||
- Drag and drop now handles correctly text/uri-list
|
||||
- Support for Terminal=true
|
||||
- Support for %f and %F
|
||||
- Configuration changes:
|
||||
- Removed primary_monitor_first as it was conflicting with taskbar behavior; use *_monitor = primary instead.
|
||||
- Other:
|
||||
- Major code refactoring
|
||||
- Dropping "0." from the version number and no longer using semver ("Breaking.Feature.Fix").
|
||||
- Tint2 will always strive to be backwards compatible with respect to the configuration format.
|
||||
- Very few configurations changes have been broken between 2010 (0.10) - 2017 (0.14);
|
||||
in all cases they were minor options that caused incorrect behavior,
|
||||
and the changes were described better by "Feature" or "Fix".
|
||||
- Practically all releases starting from 0.10 have been very stable,
|
||||
so there is no point in staying in "0." anymore.
|
||||
- But I don't want the project to get stuck in "1." forever.
|
||||
- The new versioning scheme is the following:
|
||||
- Version numbers will have the format "Feature.Fix", where:
|
||||
- "Feature" is increased when significant new features are added.
|
||||
- "Fix" is increased for bugfixes or minor changes.
|
||||
- 0.14.6 will be followed by 15.0.
|
||||
|
||||
2017-06-11 0.14.6
|
||||
- Fixes:
|
||||
- Take into account border width when computing text height
|
||||
- Taskbar: Fix task icon size limits
|
||||
- Executor: Do not output last line if it is not terminated by newline
|
||||
- Enhancements:
|
||||
- Re-execute tint2 on SIGUSR2.
|
||||
This is useful for preserving config options and environment when updating tint2.
|
||||
|
||||
2017-05-21 0.14.5
|
||||
- Fixes:
|
||||
- Fixed a couple of memory leaks
|
||||
|
||||
2017-04-29 0.14.4
|
||||
- Fixes:
|
||||
- Fix regression in executor (issue #639)
|
||||
- Fix crash when _NET_WM_ICON is set but empty (https://github.com/jmc-88/tint3/issues/21)
|
||||
|
||||
2017-04-23 0.14.3
|
||||
- Fixes:
|
||||
- Make versioning more robust when building as package
|
||||
- Enhancements:
|
||||
@@ -884,3 +950,5 @@ released tint-0.2
|
||||
2008-04-22
|
||||
- fork ttm projet from p://code.google.com/p/ttm/ (by Pål Staurland staura@gmail.com)
|
||||
while the projet is no longer in developpement, have not changed the name of 'tint'.
|
||||
.
|
||||
.
|
||||
|
||||
13
README.md
13
README.md
@@ -1,5 +1,5 @@
|
||||
# Latest stable release: 0.14.1
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/0.14.1/ChangeLog
|
||||
# Latest stable release: 15.1
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/15.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 0.14.1
|
||||
git checkout 15.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -85,7 +85,7 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
||||
|
||||
## Various configs:
|
||||
|
||||

|
||||
* [Screenshots](https://gitlab.com/o9000/tint2/wikis/screenshots)
|
||||
|
||||
## Demos
|
||||
|
||||
@@ -93,3 +93,8 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
||||
* [Executor](https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.4.gif)
|
||||
* [Mouse over effects](https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.3.gif)
|
||||
* [Distribute size between taskbars, freespace](https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.gif)
|
||||
|
||||
## More
|
||||
|
||||
* [Tint2 wiki](https://gitlab.com/o9000/tint2/wikis/Home)
|
||||
Home)
|
||||
|
||||
@@ -364,12 +364,12 @@ gradient_id_pressed = 2
|
||||
<li><code>:</code> adds a separator. You can specify more than one. <em>(since 0.13.0)</em></li>
|
||||
</ul>
|
||||
<p>For example, <code>panel_items = STC</code> will show the systray, the taskbar and the clock (from left to right).</p></li>
|
||||
<li><p><code>panel_monitor = monitor (all or 1 or 2 or ...)</code> : Which monitor tint2 draws the panel on</p>
|
||||
<li><p><code>panel_monitor = monitor (all or primary or 1 or 2 or ...)</code> : Which monitor tint2 draws the panel on</p>
|
||||
<ul>
|
||||
<li>The first monitor is <code>1</code></li>
|
||||
<li>Use <code>panel_monitor = all</code> to get a separate panel per monitor</li>
|
||||
</ul></li>
|
||||
<li><p><code>primary_monitor_first = boolean (0 or 1)</code> : Place the primary monitor before all the other monitors in the list. <em>(since 0.12.4)</em></p></li>
|
||||
<li><p><code>primary_monitor_first = boolean (0 or 1)</code> : Place the primary monitor before all the other monitors in the list. <em>(since 0.12.4; removed in 1.0, use <code>primary</code> instead)</em></p></li>
|
||||
</ul>
|
||||
<p><img src="images/panel_padding.jpg" alt=""></p>
|
||||
<ul>
|
||||
@@ -456,6 +456,7 @@ panel_size = 94% 30
|
||||
<li><p><code>taskbar_active_background_id = integer</code> : Which background to use for the taskbar of the current virtual desktop.</p></li>
|
||||
<li><p><code>taskbar_hide_inactive_tasks = boolean (0 or 1)</code> : If enabled, the taskbar shows only the active task. <em>(since 0.12)</em></p></li>
|
||||
<li><p><code>taskbar_hide_different_monitor = boolean (0 or 1)</code> : If enabled, the taskbar shows only the tasks from the current monitor. Useful when running different tint2 instances on different monitors, each one having its own config. <em>(since 0.12)</em></p></li>
|
||||
<li><p><code>taskbar_hide_different_desktop = boolean (0 or 1)</code> : If enabled, the taskbar shows only the tasks from the current desktop. Useful to make multi-desktop taskbars more compact, but still allow desktop switching with mouse click. <em>(since 1.0)</em></p></li>
|
||||
<li><p><code>taskbar_always_show_all_desktop_tasks = boolean (0 or 1)</code> : Has effect only if <code>taskbar_mode = multi_desktop</code>. If enabled, tasks that appear on all desktops are shown on all taskbars. Otherwise, they are shown only on the taskbar of the current desktop. <em>(since 0.12.4)</em></p></li>
|
||||
<li><p><code>taskbar_sort_order = none/title/center</code> : Specifies the sort order of the tasks on the taskbar. <em>(since 0.12)</em></p>
|
||||
<ul>
|
||||
@@ -523,7 +524,7 @@ panel_size = 94% 30
|
||||
<li><p><code>systray_sort = ascending/descending/left2right/right2left</code> : Specifies the sorting order for the icons in the systray: in ascending/descending alphabetical order of the icon title, or always add icons to the right/left (note that with <code>left2right</code> or <code>right2left</code> the order can be different on panel restart).</p></li>
|
||||
<li><p><code>systray_icon_size = max_icon_size</code> : Set the maximum system tray icon size to <code>number</code>. Set to <code>0</code> for automatic icon sizing.</p></li>
|
||||
<li><p><code>systray_icon_asb = alpha (0 to 100) saturation (-100 to 100) brightness (-100 to 100)</code> : Adjust the systray icons color and transparency.</p></li>
|
||||
<li><p><code>systray_monitor = integer (1, 2, ...)</code> : On which monitor to draw the systray. The first monitor is <code>1</code>. <em>(since 0.12)</em></p></li>
|
||||
<li><p><code>systray_monitor = integer (1, 2, ...) or primary</code> : On which monitor to draw the systray. The first monitor is <code>1</code>. <em>(since 0.12)</em></p></li>
|
||||
<li><p><code>systray_name_filter = string</code> : Regular expression to identify icon names to be hidden. For example, <code>^audacious$</code> will hide icons with the exact name <code>audacious</code>, while <code>aud</code> will hide any icons having <code>aud</code> in the name. <em>(since 0.13.1)</em></p></li>
|
||||
</ul>
|
||||
<h3 id="clock">Clock<a name="clock" href="#clock" class="md2man-permalink" title="permalink"></a></h3>
|
||||
@@ -566,9 +567,19 @@ panel_size = 94% 30
|
||||
<li><p><code>battery_hide = never/integer (0 to 100)</code> : At what battery percentage the battery item is hidden.</p></li>
|
||||
<li><p><code>battery_low_status = integer</code>: At what battery percentage the low command is executed.</p></li>
|
||||
<li><p><code>battery_low_cmd = notify-send "battery low"</code> : Command to execute when the battery is low.</p></li>
|
||||
<li><p><code>battery_full_cmd = notify-send "battery full"</code> : Command to execute when the battery is full.</p></li>
|
||||
<li><p><code>bat1_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||
<li><p><code>bat2_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||
<li><p><code>battery_font_color = color opacity (0 to 100)</code></p></li>
|
||||
<li><p><code>bat1_format = FORMAT_STRING</code> : Format for battery line 1. Default: %p. <em>(since 1.0)</em> Format specification:</p>
|
||||
<ul>
|
||||
<li>%s: State (charging, discharging, full, unknown).</li>
|
||||
<li>%m: Minutes left until completely charged/discharged (estimated).</li>
|
||||
<li>%h: Hours left until completely charged/discharged (estimated).</li>
|
||||
<li>%t: Time left. Shows "hrs:mins" when charging/discharging, or "Ful\" when full.</li>
|
||||
<li>%p: Percentage. Includes the % sign.</li>
|
||||
</ul></li>
|
||||
<li><p><code>bat2_format = FORMAT_STRING</code> : Format for battery line 2. Default: %t. <em>(since 1.0)</em></p></li>
|
||||
<li><p><code>battery_padding = horizontal_padding vertical_padding</code></p></li>
|
||||
<li><p><code>battery_background_id = integer</code> : Which background to use for the battery.</p></li>
|
||||
<li><p><code>battery_tooltip_enabled = boolean (0 or 1)</code> : Enable/disable battery tooltips. <em>(since 0.12.3)</em></p></li>
|
||||
@@ -683,6 +694,7 @@ execp_interval = 1
|
||||
It is based on ttm, originally written by Pål Staurland <a href="mailto:staura@gmail.com">staura@gmail.com</a>.</p><p>This manual page was originally written by Daniel Moerner <a href="mailto:dmoerner@gmail.com">dmoerner@gmail.com</a>, for the Debian project (but may be used by others).
|
||||
It was adopted from the tint2 docs.</p><h2 id="see-also">SEE ALSO<a name="see-also" href="#see-also" class="md2man-permalink" title="permalink"></a></h2><p>The main website <a href="https://gitlab.com/o9000/tint2">https://gitlab.com/o9000/tint2</a>
|
||||
and the wiki page at <a href="https://gitlab.com/o9000/tint2/wikis/home">https://gitlab.com/o9000/tint2/wikis/home</a>.</p><p>This documentation is also provided in HTML and Markdown format in the system's default location
|
||||
for documentation files, usually <code>/usr/share/doc/tint2</code> or <code>/usr/local/share/doc/tint2</code>.</p>
|
||||
for documentation files, usually <code>/usr/share/doc/tint2</code> or <code>/usr/local/share/doc/tint2</code>.
|
||||
.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -199,9 +199,9 @@ pre {
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="latest-stable-release-0-14-1"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">0.14.1</span><a name="latest-stable-release-0-14-1" href="#latest-stable-release-0-14-1" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/0.14.1/ChangeLog">https://gitlab.com/o9000/tint2/blob/0.14.1/ChangeLog</a></p><p>Documentation: <a href="manual.html">manual.html</a></p><p>Compile it with (after you install the <a href="https://gitlab.com/o9000/tint2/wikis/Install#dependencies">dependencies</a>):</p><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git
|
||||
<h1 id="latest-stable-release-15-1"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">15.1</span><a name="latest-stable-release-15-1" href="#latest-stable-release-15-1" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/15.1/ChangeLog">https://gitlab.com/o9000/tint2/blob/15.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 0.14.1
|
||||
git checkout 15.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -256,12 +256,21 @@ update-mime-database /usr/local/share/mime
|
||||
<li>Downloads: <a href="https://gitlab.com/o9000/tint2-archive/tree/master">https://gitlab.com/o9000/tint2-archive/tree/master</a> or <a href="https://code.google.com/p/tint2/downloads/list">https://code.google.com/p/tint2/downloads/list</a></li>
|
||||
<li>Old project location (inactive): <a href="https://code.google.com/p/tint2">https://code.google.com/p/tint2</a></li>
|
||||
</ul>
|
||||
<h1 id="screenshots">Screenshots<a name="screenshots" href="#screenshots" class="md2man-permalink" title="permalink"></a></h1><h2 id="default-config">Default config:<a name="default-config" href="#default-config" class="md2man-permalink" title="permalink"></a></h2><p><img src="https://gitlab.com/o9000/tint2/uploads/948fa74eca60864352a033580350b4c3/Screenshot_2016-01-23_14-42-57.png" alt="Screenshot_2016-01-23_14-42-57"></p><h2 id="various-configs">Various configs:<a name="various-configs" href="#various-configs" class="md2man-permalink" title="permalink"></a></h2><p><img src="https://gitlab.com/o9000/tint2/wikis/screenshot.png" alt="screenshot"></p><h2 id="demos">Demos<a name="demos" href="#demos" class="md2man-permalink" title="permalink"></a></h2>
|
||||
<h1 id="screenshots">Screenshots<a name="screenshots" href="#screenshots" class="md2man-permalink" title="permalink"></a></h1><h2 id="default-config">Default config:<a name="default-config" href="#default-config" class="md2man-permalink" title="permalink"></a></h2><p><img src="https://gitlab.com/o9000/tint2/uploads/948fa74eca60864352a033580350b4c3/Screenshot_2016-01-23_14-42-57.png" alt="Screenshot_2016-01-23_14-42-57"></p><h2 id="various-configs">Various configs:<a name="various-configs" href="#various-configs" class="md2man-permalink" title="permalink"></a></h2>
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/screenshots">Screenshots</a></li>
|
||||
</ul>
|
||||
<h2 id="demos">Demos<a name="demos" href="#demos" class="md2man-permalink" title="permalink"></a></h2>
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/whats-new-0.13.0.gif">Compact panel, separator, color gradients</a></li>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.4.gif">Executor</a></li>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.3.gif">Mouse over effects</a></li>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/whats-new-0.12.gif">Distribute size between taskbars, freespace</a></li>
|
||||
</ul>
|
||||
<h2 id="more">More<a name="more" href="#more" class="md2man-permalink" title="permalink"></a></h2>
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/Home">Tint2 wiki</a>
|
||||
Home)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
29
doc/tint2.1
29
doc/tint2.1
@@ -1,4 +1,4 @@
|
||||
.TH TINT2 1 "2017\-04\-23" 0.14.2
|
||||
.TH TINT2 1 "2017\-09\-08" 15.1
|
||||
.SH NAME
|
||||
.PP
|
||||
tint2 \- lightweight panel/taskbar
|
||||
@@ -309,7 +309,7 @@ gradient_id_pressed = 2
|
||||
.PP
|
||||
For example, \fB\fCpanel_items = STC\fR will show the systray, the taskbar and the clock (from left to right).
|
||||
.IP \(bu 2
|
||||
\fB\fCpanel_monitor = monitor (all or 1 or 2 or ...)\fR : Which monitor tint2 draws the panel on
|
||||
\fB\fCpanel_monitor = monitor (all or primary or 1 or 2 or ...)\fR : Which monitor tint2 draws the panel on
|
||||
.RS
|
||||
.IP \(bu 2
|
||||
The first monitor is \fB\fC1\fR
|
||||
@@ -317,7 +317,7 @@ The first monitor is \fB\fC1\fR
|
||||
Use \fB\fCpanel_monitor = all\fR to get a separate panel per monitor
|
||||
.RE
|
||||
.IP \(bu 2
|
||||
\fB\fCprimary_monitor_first = boolean (0 or 1)\fR : Place the primary monitor before all the other monitors in the list. \fI(since 0.12.4)\fP
|
||||
\fB\fCprimary_monitor_first = boolean (0 or 1)\fR : Place the primary monitor before all the other monitors in the list. \fI(since 0.12.4; removed in 1.0, use \fB\fCprimary\fR instead)\fP
|
||||
.RE
|
||||
.PP
|
||||
[](images/panel_padding.jpg)
|
||||
@@ -461,6 +461,8 @@ You can switch between virtual desktops.
|
||||
.IP \(bu 2
|
||||
\fB\fCtaskbar_hide_different_monitor = boolean (0 or 1)\fR : If enabled, the taskbar shows only the tasks from the current monitor. Useful when running different tint2 instances on different monitors, each one having its own config. \fI(since 0.12)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCtaskbar_hide_different_desktop = boolean (0 or 1)\fR : If enabled, the taskbar shows only the tasks from the current desktop. Useful to make multi\-desktop taskbars more compact, but still allow desktop switching with mouse click. \fI(since 1.0)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCtaskbar_always_show_all_desktop_tasks = boolean (0 or 1)\fR : Has effect only if \fB\fCtaskbar_mode = multi_desktop\fR\&. If enabled, tasks that appear on all desktops are shown on all taskbars. Otherwise, they are shown only on the taskbar of the current desktop. \fI(since 0.12.4)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCtaskbar_sort_order = none/title/center\fR : Specifies the sort order of the tasks on the taskbar. \fI(since 0.12)\fP
|
||||
@@ -578,7 +580,7 @@ The action semantics:
|
||||
.IP \(bu 2
|
||||
\fB\fCsystray_icon_asb = alpha (0 to 100) saturation (\-100 to 100) brightness (\-100 to 100)\fR : Adjust the systray icons color and transparency.
|
||||
.IP \(bu 2
|
||||
\fB\fCsystray_monitor = integer (1, 2, ...)\fR : On which monitor to draw the systray. The first monitor is \fB\fC1\fR\&. \fI(since 0.12)\fP
|
||||
\fB\fCsystray_monitor = integer (1, 2, ...) or primary\fR : On which monitor to draw the systray. The first monitor is \fB\fC1\fR\&. \fI(since 0.12)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCsystray_name_filter = string\fR : Regular expression to identify icon names to be hidden. For example, \fB\fC^audacious$\fR will hide icons with the exact name \fB\fCaudacious\fR, while \fB\fCaud\fR will hide any icons having \fB\fCaud\fR in the name. \fI(since 0.13.1)\fP
|
||||
.RE
|
||||
@@ -651,12 +653,30 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_low_cmd = notify\-send "battery low"\fR : Command to execute when the battery is low.
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_full_cmd = notify\-send "battery full"\fR : Command to execute when the battery is full.
|
||||
.IP \(bu 2
|
||||
\fB\fCbat1_font = [FAMILY\-LIST] [STYLE\-OPTIONS] [SIZE]\fR
|
||||
.IP \(bu 2
|
||||
\fB\fCbat2_font = [FAMILY\-LIST] [STYLE\-OPTIONS] [SIZE]\fR
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_font_color = color opacity (0 to 100)\fR
|
||||
.IP \(bu 2
|
||||
\fB\fCbat1_format = FORMAT_STRING\fR : Format for battery line 1. Default: %p. \fI(since 1.0)\fP Format specification:
|
||||
.RS
|
||||
.IP \(bu 2
|
||||
%s: State (charging, discharging, full, unknown).
|
||||
.IP \(bu 2
|
||||
%m: Minutes left until completely charged/discharged (estimated).
|
||||
.IP \(bu 2
|
||||
%h: Hours left until completely charged/discharged (estimated).
|
||||
.IP \(bu 2
|
||||
%t: Time left. Shows "hrs:mins" when charging/discharging, or "Ful\[rs]" when full.
|
||||
.IP \(bu 2
|
||||
%p: Percentage. Includes the % sign.
|
||||
.RE
|
||||
.IP \(bu 2
|
||||
\fB\fCbat2_format = FORMAT_STRING\fR : Format for battery line 2. Default: %t. \fI(since 1.0)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_padding = horizontal_padding vertical_padding\fR
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_background_id = integer\fR : Which background to use for the battery.
|
||||
@@ -875,3 +895,4 @@ and the wiki page at \[la]https://gitlab.com/o9000/tint2/wikis/home\[ra]\&.
|
||||
.PP
|
||||
This documentation is also provided in HTML and Markdown format in the system's default location
|
||||
for documentation files, usually \fB\fC/usr/share/doc/tint2\fR or \fB\fC/usr/local/share/doc/tint2\fR\&.
|
||||
\&.
|
||||
|
||||
22
doc/tint2.md
22
doc/tint2.md
@@ -1,4 +1,4 @@
|
||||
# TINT2 1 "2017-04-23" 0.14.2
|
||||
# TINT2 1 "2017-09-08" 15.1
|
||||
|
||||
## NAME
|
||||
tint2 - lightweight panel/taskbar
|
||||
@@ -258,11 +258,11 @@ gradient_id_pressed = 2
|
||||
|
||||
For example, `panel_items = STC` will show the systray, the taskbar and the clock (from left to right).
|
||||
|
||||
* `panel_monitor = monitor (all or 1 or 2 or ...)` : Which monitor tint2 draws the panel on
|
||||
* `panel_monitor = monitor (all or primary or 1 or 2 or ...)` : Which monitor tint2 draws the panel on
|
||||
* The first monitor is `1`
|
||||
* Use `panel_monitor = all` to get a separate panel per monitor
|
||||
|
||||
* `primary_monitor_first = boolean (0 or 1)` : Place the primary monitor before all the other monitors in the list. *(since 0.12.4)*
|
||||
* `primary_monitor_first = boolean (0 or 1)` : Place the primary monitor before all the other monitors in the list. *(since 0.12.4; removed in 1.0, use `primary` instead)*
|
||||
|
||||

|
||||
|
||||
@@ -370,6 +370,8 @@ panel_size = 94% 30
|
||||
|
||||
* `taskbar_hide_different_monitor = boolean (0 or 1)` : If enabled, the taskbar shows only the tasks from the current monitor. Useful when running different tint2 instances on different monitors, each one having its own config. *(since 0.12)*
|
||||
|
||||
* `taskbar_hide_different_desktop = boolean (0 or 1)` : If enabled, the taskbar shows only the tasks from the current desktop. Useful to make multi-desktop taskbars more compact, but still allow desktop switching with mouse click. *(since 1.0)*
|
||||
|
||||
* `taskbar_always_show_all_desktop_tasks = boolean (0 or 1)` : Has effect only if `taskbar_mode = multi_desktop`. If enabled, tasks that appear on all desktops are shown on all taskbars. Otherwise, they are shown only on the taskbar of the current desktop. *(since 0.12.4)*
|
||||
|
||||
* `taskbar_sort_order = none/title/center` : Specifies the sort order of the tasks on the taskbar. *(since 0.12)*
|
||||
@@ -471,7 +473,7 @@ The action semantics:
|
||||
|
||||
* `systray_icon_asb = alpha (0 to 100) saturation (-100 to 100) brightness (-100 to 100)` : Adjust the systray icons color and transparency.
|
||||
|
||||
* `systray_monitor = integer (1, 2, ...)` : On which monitor to draw the systray. The first monitor is `1`. *(since 0.12)*
|
||||
* `systray_monitor = integer (1, 2, ...) or primary` : On which monitor to draw the systray. The first monitor is `1`. *(since 0.12)*
|
||||
|
||||
* `systray_name_filter = string` : Regular expression to identify icon names to be hidden. For example, `^audacious$` will hide icons with the exact name `audacious`, while `aud` will hide any icons having `aud` in the name. *(since 0.13.1)*
|
||||
|
||||
@@ -534,12 +536,23 @@ The action semantics:
|
||||
|
||||
* `battery_low_cmd = notify-send "battery low"` : Command to execute when the battery is low.
|
||||
|
||||
* `battery_full_cmd = notify-send "battery full"` : Command to execute when the battery is full.
|
||||
|
||||
* `bat1_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]`
|
||||
|
||||
* `bat2_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]`
|
||||
|
||||
* `battery_font_color = color opacity (0 to 100)`
|
||||
|
||||
* `bat1_format = FORMAT_STRING` : Format for battery line 1. Default: %p. *(since 1.0)* Format specification:
|
||||
* %s: State (charging, discharging, full, unknown).
|
||||
* %m: Minutes left until completely charged/discharged (estimated).
|
||||
* %h: Hours left until completely charged/discharged (estimated).
|
||||
* %t: Time left. Shows "hrs:mins" when charging/discharging, or "Ful\" when full.
|
||||
* %p: Percentage. Includes the % sign.
|
||||
|
||||
* `bat2_format = FORMAT_STRING` : Format for battery line 2. Default: %t. *(since 1.0)*
|
||||
|
||||
* `battery_padding = horizontal_padding vertical_padding`
|
||||
|
||||
* `battery_background_id = integer` : Which background to use for the battery.
|
||||
@@ -739,3 +752,4 @@ and the wiki page at https://gitlab.com/o9000/tint2/wikis/home.
|
||||
|
||||
This documentation is also provided in HTML and Markdown format in the system's default location
|
||||
for documentation files, usually `/usr/share/doc/tint2` or `/usr/local/share/doc/tint2`.
|
||||
.
|
||||
|
||||
@@ -33,10 +33,11 @@ then
|
||||
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
|
||||
VERSION=$(head -n 1 ChangeLog || head -n 1 ../ChangeLog | cut -d ' ' -f 2)
|
||||
if [ $VERSION = "master" ]
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
VERSION=$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 2)
|
||||
if [ "$VERSION" = "master" ]
|
||||
then
|
||||
VERSION=$VERSION-$(head -n 1 ChangeLog || head -n 1 ../ChangeLog | cut -d ' ' -f 1)
|
||||
VERSION=$VERSION-$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 1)
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
118
new-release.py
118
new-release.py
@@ -76,37 +76,21 @@ def get_last_version():
|
||||
return tags[-1]
|
||||
|
||||
|
||||
def inc_version(v, major=False, minor=False, rc=False):
|
||||
if "-rc" in v:
|
||||
# v4.0-rc7 -> v4.0-rc8 or v4.0
|
||||
if minor:
|
||||
return v.split("-rc")[0]
|
||||
else:
|
||||
parts = v.split("-rc")
|
||||
parts[-1] = str(int(parts[-1]) + 1)
|
||||
return "-rc".join(parts)
|
||||
def inc_version(v, feature=False):
|
||||
if v.startswith("v0."):
|
||||
assert v == "v0.14.6"
|
||||
return "v15.0"
|
||||
# v4.11 -> v4.12 or v5.0
|
||||
parts = v.split(".")
|
||||
while len(parts) < 2:
|
||||
parts.append("0")
|
||||
assert len(parts) == 2
|
||||
if feature:
|
||||
parts[-2] = "v" + str(int(parts[-2].replace("v", "")) + 1)
|
||||
parts[-1] = "0"
|
||||
else:
|
||||
# v4.11 = v4, 11, 0 -> v4.11.1 or v4.12 or v.4.12-rc1 or v5.0 or v5.0-rc1
|
||||
# v4.11.7 = v4, 11, 7 -> ...
|
||||
parts = v.split(".")
|
||||
while len(parts) < 3:
|
||||
parts.append("0")
|
||||
assert len(parts) == 3
|
||||
if major:
|
||||
parts[-3] = "v" + str(int(parts[-3].replace("v", "")) + 1)
|
||||
parts[-2] = "0"
|
||||
if rc:
|
||||
parts[-2] += "-rc1"
|
||||
parts[-1] = ""
|
||||
elif minor or rc:
|
||||
parts[-2] = str(int(parts[-2]) + 1)
|
||||
if rc:
|
||||
parts[-2] += "-rc1"
|
||||
parts[-1] = ""
|
||||
else:
|
||||
parts[-1] = str(int(parts[-1]) + 1)
|
||||
assert not rc
|
||||
return ".".join([s for s in parts if s])
|
||||
parts[-1] = str(int(parts[-1]) + 1)
|
||||
return ".".join([s for s in parts if s])
|
||||
|
||||
|
||||
def assert_equal(a, b):
|
||||
@@ -117,53 +101,23 @@ def assert_equal(a, b):
|
||||
|
||||
def test_inc_version():
|
||||
# auto
|
||||
assert_equal(inc_version("v1.0"), "v1.0.1")
|
||||
assert_equal(inc_version("v1.0.1"), "v1.0.2")
|
||||
assert_equal(inc_version("v1.0.2"), "v1.0.3")
|
||||
assert_equal(inc_version("v1.0.10"), "v1.0.11")
|
||||
assert_equal(inc_version("v1.1.10"), "v1.1.11")
|
||||
assert_equal(inc_version("v1.1.10"), "v1.1.11")
|
||||
# rc
|
||||
assert_equal(inc_version("v1.0", False, False, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.1", False, False, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.2", False, False, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.10", False, False, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.1.10", False, False, True), "v1.2-rc1")
|
||||
assert_equal(inc_version("v1.1.10", False, False, True), "v1.2-rc1")
|
||||
# minor
|
||||
assert_equal(inc_version("v1.0", False, True, False), "v1.1")
|
||||
assert_equal(inc_version("v1.0.1", False, True, False), "v1.1")
|
||||
assert_equal(inc_version("v1.0.2", False, True, False), "v1.1")
|
||||
assert_equal(inc_version("v1.0.10", False, True, False), "v1.1")
|
||||
assert_equal(inc_version("v1.1.10", False, True, False), "v1.2")
|
||||
assert_equal(inc_version("v1.1.10", False, True, False), "v1.2")
|
||||
# minor rc
|
||||
assert_equal(inc_version("v1.0", False, True, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.1", False, True, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.2", False, True, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.0.10", False, True, True), "v1.1-rc1")
|
||||
assert_equal(inc_version("v1.1.10", False, True, True), "v1.2-rc1")
|
||||
assert_equal(inc_version("v1.1.10", False, True, True), "v1.2-rc1")
|
||||
# major rc
|
||||
assert_equal(inc_version("v1.0", True, False, True), "v2.0-rc1")
|
||||
assert_equal(inc_version("v1.0.1", True, False, True), "v2.0-rc1")
|
||||
assert_equal(inc_version("v1.0.2", True, False, True), "v2.0-rc1")
|
||||
assert_equal(inc_version("v1.0.10", True, False, True), "v2.0-rc1")
|
||||
assert_equal(inc_version("v1.1.10", True, False, True), "v2.0-rc1")
|
||||
assert_equal(inc_version("v1.1.10", True, False, True), "v2.0-rc1")
|
||||
# major
|
||||
assert_equal(inc_version("v1.0", True), "v2.0")
|
||||
assert_equal(inc_version("v1.0.1", True), "v2.0")
|
||||
assert_equal(inc_version("v1.0.2", True), "v2.0")
|
||||
assert_equal(inc_version("v1.0.10", True), "v2.0")
|
||||
assert_equal(inc_version("v1.1.10", True), "v2.0")
|
||||
assert_equal(inc_version("v1.1.10", True), "v2.0")
|
||||
# rc auto
|
||||
assert_equal(inc_version("v1.0-rc1"), "v1.0-rc2")
|
||||
assert_equal(inc_version("v1.1-rc2"), "v1.1-rc3")
|
||||
# rc minor
|
||||
assert_equal(inc_version("v1.0-rc1", False, True), "v1.0")
|
||||
assert_equal(inc_version("v1.1-rc2", False, True), "v1.1")
|
||||
assert_equal(inc_version("v0.14.6"), "v15.0")
|
||||
assert_equal(inc_version("v15"), "v15.1")
|
||||
assert_equal(inc_version("v15.0"), "v15.1")
|
||||
assert_equal(inc_version("v16.1"), "v16.2")
|
||||
assert_equal(inc_version("v16.10"), "v16.11")
|
||||
# fix
|
||||
assert_equal(inc_version("v0.14.6", False), "v15.0")
|
||||
assert_equal(inc_version("v15", False), "v15.1")
|
||||
assert_equal(inc_version("v15.0", False), "v15.1")
|
||||
assert_equal(inc_version("v16.1", False), "v16.2")
|
||||
assert_equal(inc_version("v16.10", False), "v16.11")
|
||||
# feature
|
||||
assert_equal(inc_version("v15", True), "v16.0")
|
||||
assert_equal(inc_version("v15.0", True), "v16.0")
|
||||
assert_equal(inc_version("v15.1", True), "v16.0")
|
||||
assert_equal(inc_version("v15.2", True), "v16.0")
|
||||
assert_equal(inc_version("v15.10", True), "v16.0")
|
||||
|
||||
|
||||
def replace_in_file(path, before, after):
|
||||
@@ -198,9 +152,7 @@ def update_log(path, version, date):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--major", action="store_true")
|
||||
parser.add_argument("--minor", action="store_true")
|
||||
parser.add_argument("--rc", action="store_true")
|
||||
parser.add_argument("--feature", action="store_true")
|
||||
parser.add_argument("--undo", action="store_true")
|
||||
args = parser.parse_args()
|
||||
logging.basicConfig(format=ansi_lblue + "%(asctime)s %(pathname)s %(levelname)s" + ansi_reset + " %(message)s", level=logging.DEBUG)
|
||||
@@ -217,7 +169,7 @@ if __name__ == '__main__':
|
||||
os.system("git log -1")
|
||||
sys.exit(0)
|
||||
info("Old version:", old_version)
|
||||
version = inc_version(old_version, args.major, args.minor, args.rc)
|
||||
version = inc_version(old_version, args.feature)
|
||||
readable_version = version.replace("v", "")
|
||||
date = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
info("New version:", readable_version, version, date)
|
||||
@@ -226,7 +178,7 @@ if __name__ == '__main__':
|
||||
# Disallow uncommitted changes in the index
|
||||
run("git diff-index --cached --quiet HEAD --ignore-submodules --")
|
||||
# Update version string
|
||||
replace_in_file("README.md", old_version, readable_version)
|
||||
replace_in_file("README.md", old_version.replace("v", ""), readable_version)
|
||||
update_man("doc/tint2.md", readable_version, date)
|
||||
update_log("ChangeLog", readable_version, date)
|
||||
run("git commit -am 'Release %s'" % readable_version)
|
||||
@@ -237,4 +189,4 @@ if __name__ == '__main__':
|
||||
run("tar -xzf tint2-%s.tar.gz" % readable_version)
|
||||
run("cd tint2-%s ; mkdir build ; cd build ; cmake .. ; make" % readable_version)
|
||||
assert_equal(run("./tint2-%s/build/tint2 -v" % readable_version).strip(), "tint2 version %s" % readable_version)
|
||||
os.system("git log -p -1")
|
||||
os.system("git log -p -1 --word-diff")
|
||||
|
||||
@@ -23,7 +23,8 @@ Homepage: https://gitlab.com/o9000/tint2/
|
||||
Package: tint2
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
${misc:Depends},
|
||||
procps
|
||||
Description: lightweight taskbar
|
||||
Tint is a simple panel/taskbar intentionally made for openbox3, but should
|
||||
also work with other window managers. The taskbar includes transparency and
|
||||
|
||||
2
packaging/debian/postinst
Normal file
2
packaging/debian/postinst
Normal file
@@ -0,0 +1,2 @@
|
||||
pkill -SIGUSR2 tint2 || true
|
||||
|
||||
@@ -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 precise trusty xenial yakkety zesty
|
||||
for DISTRO in trusty xenial zesty artful
|
||||
do
|
||||
# Cleanup from previous builds
|
||||
rm -rf tint2_$VERSION-*
|
||||
|
||||
408
packaging/version_status.py
Executable file
408
packaging/version_status.py
Executable file
@@ -0,0 +1,408 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
import ftplib
|
||||
import gzip
|
||||
import json
|
||||
import re
|
||||
from StringIO import StringIO
|
||||
import urllib2
|
||||
|
||||
|
||||
# Returns true if `value` is an integer represented as a string.
|
||||
def is_int(value):
|
||||
# type: (str) -> bool
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Returns a new string with all instances of multiple whitespace
|
||||
# replaced with a single space.
|
||||
def collapse_multiple_spaces(line):
|
||||
# type: (str) -> str
|
||||
return " ".join(line.split())
|
||||
|
||||
|
||||
# Extracts the file name from a line of an FTP listing.
|
||||
# The input must be a valid directory entry (starting with "-" or "d").
|
||||
def ftp_file_name_from_listing(line):
|
||||
# type: (str) -> str
|
||||
line = collapse_multiple_spaces(line)
|
||||
return line.split(" ", 8)[-1]
|
||||
|
||||
|
||||
# Extracts a list of the directories and a list of the files
|
||||
# from an FTP listing.
|
||||
def ftp_list_dir_process_listing(lines):
|
||||
# type: (List[str]) -> List[str], List[str]
|
||||
dirs = []
|
||||
files = []
|
||||
for line in lines:
|
||||
if line.startswith("d"):
|
||||
dirs.append(ftp_file_name_from_listing(line))
|
||||
elif line.startswith("-"):
|
||||
files.append(ftp_file_name_from_listing(line))
|
||||
return dirs, files
|
||||
|
||||
|
||||
# Lists the remote FTP directory located at `path`.
|
||||
# Returns a list of the directories and a list of the files.
|
||||
def ftp_list_dir(ftp, path):
|
||||
# type: (ftplib.FTP, str) -> List[str], List[str]
|
||||
ftp.cwd(path)
|
||||
lines = []
|
||||
ftp.retrlines("LIST", lines.append)
|
||||
return ftp_list_dir_process_listing(lines)
|
||||
|
||||
|
||||
# Downloads a binary file to a string.
|
||||
# Returns the string.
|
||||
def ftp_download(ftp, path):
|
||||
# type: (ftplib.FTP, str) -> str
|
||||
blocks = []
|
||||
ftp.retrbinary("RETR {0}".format(path), blocks.append)
|
||||
return "".join(blocks)
|
||||
|
||||
|
||||
# Extracts the list of links from an HTML string.
|
||||
def http_links_from_listing(html):
|
||||
# type: (str) -> List[str]
|
||||
pattern = re.compile(r"""href=['"]+([^'"]+)['"]+""")
|
||||
return re.findall(pattern, html)
|
||||
|
||||
|
||||
# Extracts the list of paths (relative links, except to ../*) from an HTML string.
|
||||
def http_paths_from_listing(html):
|
||||
# type: (str) -> List[str]
|
||||
paths = []
|
||||
for link in http_links_from_listing(html):
|
||||
if link.startswith(".."):
|
||||
continue
|
||||
if link == "./" or link == "/":
|
||||
continue
|
||||
if "://" in link:
|
||||
continue
|
||||
paths.append(link)
|
||||
return paths
|
||||
|
||||
|
||||
# Downloads a file as string from an URL. Decodes correctly.
|
||||
def http_download_txt(url):
|
||||
# type: (str) -> str
|
||||
try:
|
||||
r = urllib2.urlopen(url)
|
||||
encoding = r.headers.getparam("charset")
|
||||
if not encoding:
|
||||
encoding = "utf-8"
|
||||
return r.read().decode(encoding)
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
# Extracts the list of paths (relative links, except to ../*) from the HTML code
|
||||
# located at `url`.
|
||||
def http_list_dir(url):
|
||||
# type: (str) -> List[str]
|
||||
try:
|
||||
html = http_download_txt(url)
|
||||
except:
|
||||
return []
|
||||
return http_paths_from_listing(html)
|
||||
|
||||
|
||||
# Extracts the version and maintainer info for a package, from a Debian repository Packages file.
|
||||
def deb_packages_extract_version(packages, name):
|
||||
# type: (str, str) -> str, str
|
||||
inside = False
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in packages.split("\n"):
|
||||
if line == "Package: " + name:
|
||||
inside = True
|
||||
elif not line:
|
||||
if inside:
|
||||
break
|
||||
else:
|
||||
if inside:
|
||||
if line.startswith("Version:"):
|
||||
version = line.split(":", 1)[-1].strip()
|
||||
elif line.startswith("Maintainer:"):
|
||||
maintainer = line.split(":", 1)[-1].strip()
|
||||
return version, maintainer
|
||||
|
||||
# Extracts the version and maintainer info for a package, from an Arch PKGBUILD file.
|
||||
def arch_pkgbuild_extract_version(pkgbuild):
|
||||
# type: (str) -> str, str
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in pkgbuild.split("\n"):
|
||||
if line.startswith("# Maintainer:"):
|
||||
maintainer = line.split(":", 1)[-1].strip()
|
||||
elif line.startswith("pkgver="):
|
||||
version = line.split("=", 1)[-1].strip()
|
||||
return version, maintainer
|
||||
|
||||
|
||||
# Debian
|
||||
|
||||
def get_debian_release_version(release):
|
||||
data = http_download_txt("http://metadata.ftp-master.debian.org/changelogs/main/t/tint2/{0}_changelog".format(release))
|
||||
version = data.split("\n", 1)[0].split("(", 1)[-1].split(")", 1)[0].strip()
|
||||
maintainer = [line.split("--", 1)[-1] for line in data.split("\n") if line.startswith(" --")][0].split(" ")[0].strip()
|
||||
return release, version, maintainer
|
||||
|
||||
|
||||
def get_debian_versions():
|
||||
return "Debian", "debian", [get_debian_release_version(release) for release in ["stable", "testing", "unstable", "experimental"]]
|
||||
|
||||
|
||||
# Ubuntu
|
||||
|
||||
def get_ubuntu_versions():
|
||||
data = http_download_txt("https://api.launchpad.net/1.0/ubuntu/+archive/primary?ws.op=getPublishedSources&source_name=tint2&exact_match=true")
|
||||
data = json.loads(data)["entries"]
|
||||
data.reverse()
|
||||
versions = []
|
||||
for package in data:
|
||||
if package["status"] == "Published":
|
||||
version = package["source_package_version"]
|
||||
release = package["distro_series_link"].split("/")[-1]
|
||||
maintainer = package["package_maintainer_link"]
|
||||
versions.append((release, version, maintainer))
|
||||
return "Ubuntu", "ubuntu", versions
|
||||
|
||||
|
||||
# BunsenLabs
|
||||
|
||||
def get_bunsenlabs_versions():
|
||||
dirs = http_list_dir("https://eu.pkg.bunsenlabs.org/debian/dists/")
|
||||
versions = []
|
||||
for d in dirs:
|
||||
if d.endswith("/") and "/" not in d[:-1]:
|
||||
release = d.replace("/", "")
|
||||
packages = http_download_txt("https://eu.pkg.bunsenlabs.org/debian/dists/{0}/main/binary-amd64/Packages".format(release))
|
||||
version, maintainer = deb_packages_extract_version(packages, "tint2")
|
||||
if version:
|
||||
versions.append((release, version, maintainer))
|
||||
return "BunsenLabs", "bunsenlabs", versions
|
||||
|
||||
|
||||
# Arch
|
||||
|
||||
def get_arch_versions():
|
||||
pkgbuild = http_download_txt("https://git.archlinux.org/svntogit/community.git/plain/trunk/PKGBUILD?h=packages/tint2")
|
||||
version, maintainer = arch_pkgbuild_extract_version(pkgbuild)
|
||||
return "Arch Linux", "archlinux", [("Community", version, maintainer)]
|
||||
|
||||
|
||||
# Fedora
|
||||
|
||||
def get_fedora_versions():
|
||||
dirs = http_list_dir("http://mirror.switch.ch/ftp/mirror/fedora/linux/development/")
|
||||
versions = []
|
||||
for d in dirs:
|
||||
if d.endswith("/") and "/" not in d[:-1]:
|
||||
release = d.replace("/", "")
|
||||
packages = http_list_dir("http://mirror.switch.ch/ftp/mirror/fedora/linux/development/{0}/Everything/source/tree/Packages/t/".format(release))
|
||||
for p in packages:
|
||||
if p.startswith("tint2-"):
|
||||
version = p.split("-", 1)[-1].split(".fc")[0]
|
||||
v = (release, version, "")
|
||||
if v not in versions:
|
||||
versions.append(v)
|
||||
return "Fedora", "fedora", versions
|
||||
|
||||
|
||||
# Red Hat (EPEL)
|
||||
|
||||
def get_redhat_epel_versions():
|
||||
dirs = http_list_dir("http://mirror.switch.ch/ftp/mirror/epel/")
|
||||
versions = []
|
||||
for d in dirs:
|
||||
if d.endswith("/") and "/" not in d[:-1] and is_int(d[:-1]):
|
||||
release = d.replace("/", "")
|
||||
packages = http_list_dir("http://mirror.switch.ch/ftp/mirror/epel/{0}/SRPMS/t/".format(release))
|
||||
for p in packages:
|
||||
if p.startswith("tint2-"):
|
||||
version = p.split("-", 1)[-1].split(".el")[0]
|
||||
v = (release, version, "")
|
||||
if v not in versions:
|
||||
versions.append(v)
|
||||
return "RedHat (EPEL)", "rhel", versions
|
||||
|
||||
|
||||
# SUSE
|
||||
|
||||
def get_suse_versions():
|
||||
ftp = ftplib.FTP("mirror.switch.ch")
|
||||
ftp.login()
|
||||
releases, _ = ftp_list_dir(ftp, "/mirror/opensuse/opensuse/distribution/leap/")
|
||||
versions = []
|
||||
for release in releases:
|
||||
root = "/mirror/opensuse/opensuse/distribution/leap/{0}/repo/oss/suse/repodata/".format(release)
|
||||
_, files = ftp_list_dir(ftp, root)
|
||||
for fname in files:
|
||||
if fname.endswith("-primary.xml.gz"):
|
||||
data = ftp_download(ftp, "{0}/{1}".format(root, fname))
|
||||
xml = gzip.GzipFile(fileobj=StringIO(data)).read()
|
||||
root = ET.fromstring(xml)
|
||||
for package in root.findall("{http://linux.duke.edu/metadata/common}package"):
|
||||
name = package.find("{http://linux.duke.edu/metadata/common}name").text
|
||||
if name == "tint2":
|
||||
version = package.find("{http://linux.duke.edu/metadata/common}version").get("ver")
|
||||
versions.append((release, version, ""))
|
||||
ftp.quit()
|
||||
return "OpenSUSE", "opensuse", versions
|
||||
|
||||
|
||||
# Gentoo
|
||||
|
||||
def get_gentoo_versions():
|
||||
files = http_list_dir("https://gitweb.gentoo.org/repo/gentoo.git/tree/x11-misc/tint2")
|
||||
versions = []
|
||||
for f in files:
|
||||
if "tint2" in f and f.endswith(".ebuild"):
|
||||
version = f.split("tint2-")[-1].split(".ebuild")[0]
|
||||
v = ("", version, "")
|
||||
if v not in versions:
|
||||
versions.append(v)
|
||||
return "Gentoo", "gentoo", versions
|
||||
|
||||
|
||||
# Void
|
||||
|
||||
def get_void_versions():
|
||||
template = http_download_txt("https://raw.githubusercontent.com/voidlinux/void-packages/master/srcpkgs/tint2/template")
|
||||
versions = []
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in template.split("\n"):
|
||||
if line.startswith("version="):
|
||||
version = line.split("=", 1)[-1].replace('"', "").strip()
|
||||
elif line.startswith("maintainer="):
|
||||
maintainer = line.split("=", 1)[-1].replace('"', "").strip()
|
||||
if version:
|
||||
versions.append(("", version, maintainer))
|
||||
return "Void Linux", "void", versions
|
||||
|
||||
|
||||
# Alpine
|
||||
|
||||
def get_alpine_versions():
|
||||
apkbuild = http_download_txt("https://git.alpinelinux.org/cgit/aports/plain/community/tint2/APKBUILD")
|
||||
versions = []
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in apkbuild.split("\n"):
|
||||
if line.startswith("pkgver="):
|
||||
version = line.split("=", 1)[-1].replace('"', "").strip()
|
||||
elif line.startswith("# Maintainer:"):
|
||||
maintainer = line.split(":", 1)[-1].replace('"', "").strip()
|
||||
if version:
|
||||
versions.append(("", version, maintainer))
|
||||
return "Alpine Linux", "alpine", versions
|
||||
|
||||
|
||||
# Slackware
|
||||
|
||||
def get_slack_versions():
|
||||
dirs = http_list_dir("https://slackbuilds.org/slackbuilds/")
|
||||
versions = []
|
||||
for d in dirs:
|
||||
if d.endswith("/") and "/" not in d[:-1]:
|
||||
release = d.replace("/", "")
|
||||
try:
|
||||
info = http_download_txt("https://slackbuilds.org/slackbuilds/{0}/desktop/tint2/tint2.info".format(release))
|
||||
except:
|
||||
continue
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in info.split("\n"):
|
||||
if line.startswith("VERSION="):
|
||||
version = line.split("=", 1)[-1].replace('"', "").strip()
|
||||
elif line.startswith("MAINTAINER="):
|
||||
maintainer = line.split("=", 1)[-1].replace('"', "").strip()
|
||||
if version:
|
||||
versions.append((release, version, maintainer))
|
||||
return "Slackware", "slackware", versions
|
||||
|
||||
# FreeBSD
|
||||
|
||||
def get_freebsd_versions():
|
||||
makefile = http_download_txt("https://svnweb.freebsd.org/ports/head/x11/tint/Makefile?view=co")
|
||||
versions = []
|
||||
version = None
|
||||
maintainer = None
|
||||
for line in makefile.split("\n"):
|
||||
if line.startswith("PORTVERSION="):
|
||||
version = line.split("=", 1)[-1].strip()
|
||||
elif line.startswith("MAINTAINER="):
|
||||
maintainer = line.split("=", 1)[-1].strip()
|
||||
if version:
|
||||
versions.append(("", version, maintainer))
|
||||
return "FreeBSD", "freebsd", versions
|
||||
|
||||
|
||||
# OpenBSD
|
||||
|
||||
def get_openbsd_versions():
|
||||
makefile = http_download_txt("http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/x11/tint2/Makefile?rev=1.5&content-type=text/plain")
|
||||
versions = []
|
||||
version = None
|
||||
for line in makefile.split("\n"):
|
||||
if line.startswith("V="):
|
||||
version = line.split("=", 1)[-1].strip()
|
||||
if version:
|
||||
versions.append(("", version, ""))
|
||||
return "OpenBSD", "openbsd", versions
|
||||
|
||||
|
||||
# Upstream
|
||||
|
||||
def get_tint2_version():
|
||||
readme = http_download_txt("https://gitlab.com/o9000/tint2/raw/master/README.md")
|
||||
version = readme.split("\n", 1)[0].split(":", 1)[-1].strip()
|
||||
return version
|
||||
|
||||
|
||||
def main():
|
||||
latest = get_tint2_version()
|
||||
distros = []
|
||||
distros.append(get_debian_versions())
|
||||
distros.append(get_bunsenlabs_versions())
|
||||
distros.append(get_ubuntu_versions())
|
||||
distros.append(get_fedora_versions())
|
||||
distros.append(get_redhat_epel_versions())
|
||||
distros.append(get_suse_versions())
|
||||
distros.append(get_alpine_versions())
|
||||
distros.append(get_slack_versions())
|
||||
distros.append(get_arch_versions())
|
||||
distros.append(get_void_versions())
|
||||
distros.append(get_gentoo_versions())
|
||||
distros.append(get_freebsd_versions())
|
||||
distros.append(get_openbsd_versions())
|
||||
print "| Distribution | Release | Version | Status |"
|
||||
print "| ------------ | ------- | ------- | ------ |"
|
||||
for dist, dcode, releases in distros:
|
||||
icon = "".format(dcode)
|
||||
for r in releases:
|
||||
if r[1].split("-", 1)[0] == latest:
|
||||
status = ":white_check_mark: Latest"
|
||||
else:
|
||||
status = ":warning: Out of date"
|
||||
print "| {0} {1} | {2} | {3} | {4} |".format(icon, dist, r[0], r[1], status)
|
||||
utc_datetime = datetime.datetime.utcnow()
|
||||
print ""
|
||||
print "Last updated:", utc_datetime.strftime("%Y-%m-%d %H:%M UTC")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
208
packaging/version_status_test.py
Executable file
208
packaging/version_status_test.py
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
from version_status import *
|
||||
|
||||
|
||||
class TestStringFunctions(unittest.TestCase):
|
||||
def test_collapse_multiple_spaces(self):
|
||||
self.assertEqual(collapse_multiple_spaces("asdf"), "asdf")
|
||||
self.assertEqual(collapse_multiple_spaces("as df"), "as df")
|
||||
self.assertEqual(collapse_multiple_spaces("as df"), "as df")
|
||||
self.assertEqual(collapse_multiple_spaces("a s d f"), "a s d f")
|
||||
|
||||
|
||||
class TestFtpFunctions(unittest.TestCase):
|
||||
def test_ftp_file_name_from_listing(self):
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18 README"), "README")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18:12 README"), "README")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18 READ ME"), "READ ME")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18:12 READ ME"), "READ ME")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18 README"), "README")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18:12 README.txt"), "README.txt")
|
||||
self.assertEqual(ftp_file_name_from_listing("-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18:12 READ ME.txt"), "READ ME.txt")
|
||||
|
||||
def test_ftp_list_dir_process_listing(self):
|
||||
lines = [ "-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18 README",
|
||||
"-rw-rw-r-- 1 1176 1176 1063 Jun 15 10:18:11 READ ME.txt",
|
||||
"drwxr-sr-x 5 1176 1176 4096 Dec 19 2000 pool",
|
||||
"drwxr-sr-x 4 1176 1176 4096 Nov 17 2008 project",
|
||||
"drwxr-xr-x 3 1176 1176 4096 Oct 10 2012 tools"]
|
||||
dirs_check = ["pool", "project", "tools"]
|
||||
files_check = ["README", "READ ME.txt"]
|
||||
dirs, files = ftp_list_dir_process_listing(lines)
|
||||
dirs.sort()
|
||||
dirs_check.sort()
|
||||
files.sort()
|
||||
files_check.sort()
|
||||
self.assertEqual(dirs, dirs_check)
|
||||
self.assertEqual(files, files_check)
|
||||
|
||||
|
||||
class TestHttpFunctions(unittest.TestCase):
|
||||
def test_http_links_from_listing(self):
|
||||
html = """<html>
|
||||
<head><title>Index of /debian/dists/</title></head>
|
||||
<body bgcolor="white">
|
||||
<a href="http://google.com">google/</a>
|
||||
<h1>Index of /debian/dists/</h1><hr><pre><a href="../">../</a>
|
||||
<a href="bunsen-hydrogen/">bunsen-hydrogen/</a> 08-May-2017 20:31 -
|
||||
<a href="jessie-backports/">jessie-backports/</a> 01-Jul-2017 15:58 -
|
||||
<a href="unstable/">unstable/</a> 12-Aug-2017 19:32 -
|
||||
</pre><hr></body>
|
||||
</html>"""
|
||||
links_check = ["../", "bunsen-hydrogen/", "jessie-backports/", "unstable/", "http://google.com"]
|
||||
links = http_links_from_listing(html)
|
||||
links.sort()
|
||||
links_check.sort()
|
||||
self.assertEqual(links, links_check)
|
||||
|
||||
def test_http_paths_from_listing(self):
|
||||
html = """<html>
|
||||
<head><title>Index of /debian/dists/</title></head>
|
||||
<body bgcolor="white">
|
||||
<h1>Index of /debian/dists/</h1><hr><pre><a href="../">../</a>
|
||||
<a href="bunsen-hydrogen/">bunsen-hydrogen/</a> 08-May-2017 20:31 -
|
||||
<a href="jessie-backports/">jessie-backports/</a> 01-Jul-2017 15:58 -
|
||||
<a href="unstable/">unstable/</a> 12-Aug-2017 19:32 -
|
||||
</pre><hr></body>
|
||||
</html>"""
|
||||
paths_check = ["bunsen-hydrogen/", "jessie-backports/", "unstable/"]
|
||||
paths = http_paths_from_listing(html)
|
||||
paths.sort()
|
||||
paths_check.sort()
|
||||
self.assertEqual(paths, paths_check)
|
||||
|
||||
|
||||
class TestPackageFunctions(unittest.TestCase):
|
||||
def test_deb_packages_extract_version(self):
|
||||
packages = """Package: sendmailanalyzer
|
||||
Version: 9.2-1.1
|
||||
Architecture: all
|
||||
Maintainer: Dominique Fournier <dominique@fournier38.fr>
|
||||
Installed-Size: 749
|
||||
Pre-Depends: perl
|
||||
Depends: apache2
|
||||
Homepage: http://sareport.darold.net/
|
||||
Priority: optional
|
||||
Section: mail
|
||||
Filename: pool/main/s/sendmailanalyzer/sendmailanalyzer_9.2-1.1_all.deb
|
||||
Size: 143576
|
||||
SHA256: 0edcbde19a23333c8c894e27af32447582b38e3ccd84122ac07720fdaab8fa0c
|
||||
SHA1: a7f4dcf42e850acf2c201bc4594cb6b765dced20
|
||||
MD5sum: adb39196fc33a826b24e9d0e440cba25
|
||||
Description: Perl Sendmail/Postfix log analyser
|
||||
SendmailAnalyzer continuously read your mail log file to generate
|
||||
periodical HTML and graph reports. All reports are shown through
|
||||
a CGI web interface.
|
||||
It reports all you ever wanted to know about email trafic on your network.
|
||||
You can also use it in ISP environment with per domain report.
|
||||
|
||||
Package: tint2
|
||||
Version: 0.14.6-1
|
||||
Architecture: amd64
|
||||
Maintainer: Jens John <dev@2ion.de>
|
||||
Installed-Size: 1230
|
||||
Depends: libatk1.0-0 (>= 1.12.4), libc6 (>= 2.15), libcairo2 (>= 1.2.4), libfontconfig1 (>= 2.11), libfreetype6 (>= 2.2.1), libgdk-pixbuf2.0-0 (>= 2.22.0), libglib2.0-0 (>= 2.35.9), libgtk2.0-0 (>= 2.14.0), libimlib2 (>= 1.4.5), libpango-1.0-0 (>= 1.20.0), libpangocairo-1.0-0 (>= 1.14.0), libpangoft2-1.0-0 (>= 1.14.0), librsvg2-2 (>= 2.14.4), libstartup-notification0 (>= 0.4), libx11-6, libxcomposite1 (>= 1:0.3-1), libxdamage1 (>= 1:1.1), libxfixes3, libxinerama1, libxrandr2 (>= 2:1.2.99.3), libxrender1
|
||||
Homepage: https://gitlab.com/o9000/tint2/
|
||||
Priority: optional
|
||||
Section: x11
|
||||
Filename: pool/main/t/tint2/tint2_0.14.6-1_amd64.deb
|
||||
Size: 279638
|
||||
SHA256: c96e745425a97828952e9e0277176fe68e2512056915560ac968a66c88a0a8b7
|
||||
SHA1: 82edd60429a494bb127e6d8a10434fca0ee60f61
|
||||
MD5sum: 65455638fb41503361560b25a70b33b7
|
||||
Description: lightweight taskbar
|
||||
Tint is a simple panel/taskbar intentionally made for openbox3, but should
|
||||
also work with other window managers. The taskbar includes transparency and
|
||||
color settings for the font, icons, border, and background. It also supports
|
||||
multihead setups, customized mouse actions, and a built-in clock. Tint was
|
||||
originally based on ttm code. Since then, support has also been added
|
||||
for a battery monitor and system tray.
|
||||
.
|
||||
The goal is to keep a clean and unintrusive look with lightweight code and
|
||||
compliance with freedesktop specification.
|
||||
|
||||
Package: xfce4-power-manager
|
||||
Version: 1.4.4-4~bpo8+1
|
||||
Architecture: amd64
|
||||
Maintainer: Debian Xfce Maintainers <pkg-xfce-devel@lists.alioth.debian.org>
|
||||
Installed-Size: 541
|
||||
Depends: libc6 (>= 2.4), libcairo2 (>= 1.2.4), libdbus-1-3 (>= 1.0.2), libdbus-glib-1-2 (>= 0.88), libgdk-pixbuf2.0-0 (>= 2.22.0), libglib2.0-0 (>= 2.41.1), libgtk2.0-0 (>= 2.24.0), libnotify4 (>= 0.7.0), libpango-1.0-0 (>= 1.14.0), libpangocairo-1.0-0 (>= 1.14.0), libupower-glib3 (>= 0.99.0), libx11-6, libxext6, libxfce4ui-1-0 (>= 4.9.0), libxfce4util6 (>= 4.9.0), libxfconf-0-2 (>= 4.6.0), libxrandr2 (>= 2:1.2.99.2), upower (>= 0.99), xfce4-power-manager-data (= 1.4.4-4~bpo8+1)
|
||||
Recommends: libpam-systemd, xfce4-power-manager-plugins
|
||||
Homepage: http://goodies.xfce.org/projects/applications/xfce4-power-manager
|
||||
Priority: optional
|
||||
Section: xfce
|
||||
Filename: pool/main/x/xfce4-power-manager/xfce4-power-manager_1.4.4-4~bpo8+1_amd64.deb
|
||||
Size: 214122
|
||||
SHA256: 992b606afe5e9934bce19a1df2b8d7067c98b9d64e23a9b63dbd0c4cf28b4ac9
|
||||
SHA1: 6bfcd77071f31577a37abab063bf21a34f4d616c
|
||||
MD5sum: fb777aecbbfe39742649b768eb22c697
|
||||
Description: power manager for Xfce desktop
|
||||
This power manager for the Xfce desktop enables laptop users to set up
|
||||
a power profile for two different modes "on battery power" and "on ac
|
||||
power" while still allowing desktop users to at least change the DPMS
|
||||
settings and CPU frequency using the settings dialogue..
|
||||
.
|
||||
It features:
|
||||
* battery monitoring
|
||||
* cpu frequency settings
|
||||
* monitor DPMS settings
|
||||
* suspend/Hibernate
|
||||
* LCD brightness control
|
||||
* Lid, sleep and power switches control"""
|
||||
version, maintainer = deb_packages_extract_version(packages, "tint2")
|
||||
self.assertEqual(version, "0.14.6-1")
|
||||
self.assertEqual(maintainer, "Jens John <dev@2ion.de>")
|
||||
version, maintainer = deb_packages_extract_version(packages, "asdf")
|
||||
self.assertEqual(version, None)
|
||||
self.assertEqual(maintainer, None)
|
||||
|
||||
def test_arch_packages_extract_version(self):
|
||||
pkgbuild = """# $Id$
|
||||
# Maintainer: Alexander F Rødseth <xyproto@archlinux.org>
|
||||
# Contributor: Blue Peppers <bluepeppers@archlinux.us>
|
||||
# Contributor: Stefan Husmann <stefan-husmann@t-online.de>
|
||||
# Contributor: Yannick LM <LMyannicklm1337@gmail.com>
|
||||
|
||||
pkgname=tint2
|
||||
pkgver=0.14.6
|
||||
pkgrel=2
|
||||
pkgdesc='Basic, good-looking task manager for WMs'
|
||||
arch=('x86_64' 'i686')
|
||||
url='https://gitlab.com/o9000/tint2'
|
||||
license=('GPL2')
|
||||
depends=('gtk2' 'imlib2' 'startup-notification')
|
||||
makedepends=('cmake' 'startup-notification' 'git' 'ninja' 'setconf')
|
||||
source=("$pkgname-$pkgver.tar.bz2::https://gitlab.com/o9000/tint2/repository/archive.tar.bz2?ref=$pkgver")
|
||||
sha256sums=('b40079fb187aa248cd3b6957076f138d040c723b309e1b254ac0c8ec9826a451')
|
||||
|
||||
prepare() {
|
||||
mv "$pkgname-$pkgver-"* "$pkgname"
|
||||
setconf "$pkgname/get_version.sh" VERSION "$pkgver"
|
||||
}
|
||||
|
||||
build() {
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake "../$pkgname" \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DENABLE_TINT2CONF=1 \
|
||||
-GNinja
|
||||
ninja
|
||||
}
|
||||
|
||||
package() {
|
||||
DESTDIR="$pkgdir" ninja -C build install
|
||||
}
|
||||
|
||||
# getver: gitlab.com/o9000/tint2/blob/master/README.md
|
||||
# vim: ts=2 sw=2 et:"""
|
||||
version, maintainer = arch_pkgbuild_extract_version(pkgbuild)
|
||||
self.assertEqual(version, "0.14.6")
|
||||
self.assertEqual(maintainer, "Alexander F Rødseth <xyproto@archlinux.org>")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -35,20 +35,25 @@ gboolean bat1_has_font;
|
||||
PangoFontDescription *bat1_font_desc;
|
||||
gboolean bat2_has_font;
|
||||
PangoFontDescription *bat2_font_desc;
|
||||
char *bat1_format;
|
||||
char *bat2_format;
|
||||
struct BatteryState battery_state;
|
||||
gboolean battery_enabled;
|
||||
gboolean battery_tooltip_enabled;
|
||||
int percentage_hide;
|
||||
static timeout *battery_timeout;
|
||||
|
||||
static char buf_bat_percentage[10];
|
||||
static char buf_bat_time[20];
|
||||
#define BATTERY_BUF_SIZE 256
|
||||
static char buf_bat_line1[BATTERY_BUF_SIZE];
|
||||
static char buf_bat_line2[BATTERY_BUF_SIZE];
|
||||
|
||||
int8_t battery_low_status;
|
||||
gboolean battery_low_cmd_sent;
|
||||
gboolean battery_full_cmd_sent;
|
||||
char *ac_connected_cmd;
|
||||
char *ac_disconnected_cmd;
|
||||
char *battery_low_cmd;
|
||||
char *battery_full_cmd;
|
||||
char *battery_lclick_command;
|
||||
char *battery_mclick_command;
|
||||
char *battery_rclick_command;
|
||||
@@ -70,14 +75,18 @@ void default_battery()
|
||||
battery_found = FALSE;
|
||||
percentage_hide = 101;
|
||||
battery_low_cmd_sent = FALSE;
|
||||
battery_full_cmd_sent = FALSE;
|
||||
battery_timeout = NULL;
|
||||
bat1_has_font = FALSE;
|
||||
bat1_font_desc = NULL;
|
||||
bat1_format = NULL;
|
||||
bat2_has_font = FALSE;
|
||||
bat2_font_desc = NULL;
|
||||
bat2_format = NULL;
|
||||
ac_connected_cmd = NULL;
|
||||
ac_disconnected_cmd = NULL;
|
||||
battery_low_cmd = NULL;
|
||||
battery_full_cmd = NULL;
|
||||
battery_lclick_command = NULL;
|
||||
battery_mclick_command = NULL;
|
||||
battery_rclick_command = NULL;
|
||||
@@ -98,6 +107,12 @@ void cleanup_battery()
|
||||
bat2_font_desc = NULL;
|
||||
free(battery_low_cmd);
|
||||
battery_low_cmd = NULL;
|
||||
free(battery_full_cmd);
|
||||
battery_full_cmd = NULL;
|
||||
free(bat1_format);
|
||||
bat1_format = NULL;
|
||||
free(bat2_format);
|
||||
bat2_format = NULL;
|
||||
free(battery_lclick_command);
|
||||
battery_lclick_command = NULL;
|
||||
free(battery_mclick_command);
|
||||
@@ -119,6 +134,91 @@ void cleanup_battery()
|
||||
battery_os_free();
|
||||
}
|
||||
|
||||
// Appends addendum to dest, and does not allow dest to grow over limit (including NULL terminator).
|
||||
char *strnappend(char *dest, const char *addendum, size_t limit)
|
||||
{
|
||||
char *tmp = strdup(dest);
|
||||
|
||||
// Actually concatenate them.
|
||||
snprintf(dest, limit, "%s%s", tmp, addendum);
|
||||
|
||||
free(tmp);
|
||||
return dest;
|
||||
}
|
||||
|
||||
void battery_update_text(char *dest, char *format)
|
||||
{
|
||||
if (!battery_enabled || !dest || !format)
|
||||
return;
|
||||
// We want to loop over the format specifier, replacing any known symbols with our battery data.
|
||||
// First, erase anything already stored in the buffer.
|
||||
// This ensures the string will always be null-terminated.
|
||||
bzero(dest, BATTERY_BUF_SIZE);
|
||||
|
||||
for (size_t o = 0; o < strlen(format); o++) {
|
||||
char buf[BATTERY_BUF_SIZE];
|
||||
bzero(buf, BATTERY_BUF_SIZE);
|
||||
char *c = &format[o];
|
||||
// Format specification:
|
||||
// %s : State (charging, discharging, full, unknown)
|
||||
// %m : Minutes left (estimated).
|
||||
// %h : Hours left (estimated).
|
||||
// %t : Time left. This is equivalent to the old behaviour; i.e. "(plugged in)" or "hrs:mins" otherwise.
|
||||
// %p : Percentage left. Includes the % sign.
|
||||
if (*c == '%') {
|
||||
c++;
|
||||
o++; // Skip the format control character.
|
||||
switch (*c) {
|
||||
case 's':
|
||||
// Append the appropriate status message to the string.
|
||||
strnappend(dest,
|
||||
(battery_state.state == BATTERY_CHARGING)
|
||||
? "Charging"
|
||||
: (battery_state.state == BATTERY_DISCHARGING)
|
||||
? "Discharging"
|
||||
: (battery_state.state == BATTERY_FULL)
|
||||
? "Full"
|
||||
: "Unknown",
|
||||
BATTERY_BUF_SIZE);
|
||||
break;
|
||||
case 'm':
|
||||
snprintf(buf, sizeof(buf), "%02d", battery_state.time.minutes);
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
break;
|
||||
case 'h':
|
||||
snprintf(buf, sizeof(buf), "%02d", battery_state.time.hours);
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
break;
|
||||
case 'p':
|
||||
snprintf(buf, sizeof(buf), "%d%%", battery_state.percentage);
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
break;
|
||||
case 't':
|
||||
if (battery_state.state == BATTERY_FULL) {
|
||||
snprintf(buf, sizeof(buf), "Full");
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes);
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
case '\0':
|
||||
strnappend(dest, "%", BATTERY_BUF_SIZE);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "tint2: Battery: unrecognised format specifier '%%%c'.\n", *c);
|
||||
buf[0] = *c;
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
}
|
||||
} else {
|
||||
buf[0] = *c;
|
||||
strnappend(dest, buf, BATTERY_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_battery()
|
||||
{
|
||||
if (!battery_enabled)
|
||||
@@ -126,8 +226,7 @@ void init_battery()
|
||||
|
||||
battery_found = battery_os_init();
|
||||
|
||||
if (!battery_timeout)
|
||||
battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout);
|
||||
battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout);
|
||||
|
||||
update_battery();
|
||||
}
|
||||
@@ -169,6 +268,11 @@ void init_battery_panel(void *p)
|
||||
if (battery_tooltip_enabled)
|
||||
battery->area._get_tooltip_text = battery_get_tooltip;
|
||||
instantiate_area_gradients(&battery->area);
|
||||
|
||||
if (!bat1_format && !bat2_format) {
|
||||
bat1_format = strdup("%p");
|
||||
bat2_format = strdup("%t");
|
||||
}
|
||||
}
|
||||
|
||||
void battery_init_fonts()
|
||||
@@ -242,6 +346,16 @@ void update_battery_tick(void *arg)
|
||||
battery_low_cmd_sent = FALSE;
|
||||
}
|
||||
|
||||
if ((battery_state.percentage >= 100 || battery_state.state == BATTERY_FULL) &&
|
||||
!battery_full_cmd_sent) {
|
||||
tint_exec_no_sn(battery_full_cmd);
|
||||
battery_full_cmd_sent = TRUE;
|
||||
}
|
||||
if (battery_state.percentage < 100 && battery_state.state != BATTERY_FULL &&
|
||||
battery_full_cmd_sent) {
|
||||
battery_full_cmd_sent = FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
// Show/hide if needed
|
||||
if (!battery_found) {
|
||||
@@ -278,158 +392,51 @@ int update_battery()
|
||||
battery_state.percentage = 100;
|
||||
}
|
||||
|
||||
battery_update_text(buf_bat_line1, bat1_format);
|
||||
if (bat2_format != 0) {
|
||||
battery_update_text(buf_bat_line2, bat2_format);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int battery_compute_desired_size(void *obj)
|
||||
{
|
||||
Battery *battery = (Battery *)obj;
|
||||
Panel *panel = (Panel *)battery->area.panel;
|
||||
int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink;
|
||||
int bat_time_height, bat_time_width, bat_time_height_ink;
|
||||
|
||||
snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage);
|
||||
if (battery_state.state == BATTERY_FULL) {
|
||||
strcpy(buf_bat_time, "Full");
|
||||
} else {
|
||||
snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes);
|
||||
}
|
||||
get_text_size2(bat1_font_desc,
|
||||
&bat_percentage_height_ink,
|
||||
&bat_percentage_height,
|
||||
&bat_percentage_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_bat_percentage,
|
||||
strlen(buf_bat_percentage),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
get_text_size2(bat2_font_desc,
|
||||
&bat_time_height_ink,
|
||||
&bat_time_height,
|
||||
&bat_time_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_bat_time,
|
||||
strlen(buf_bat_time),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
|
||||
if (panel_horizontal) {
|
||||
int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width;
|
||||
new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area);
|
||||
return new_size;
|
||||
} else {
|
||||
int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr +
|
||||
top_bottom_border_width(&battery->area);
|
||||
return new_size;
|
||||
}
|
||||
return text_area_compute_desired_size(&battery->area, buf_bat_line1, buf_bat_line2, bat1_font_desc, bat2_font_desc);
|
||||
}
|
||||
|
||||
gboolean resize_battery(void *obj)
|
||||
{
|
||||
Battery *battery = (Battery *)obj;
|
||||
Panel *panel = (Panel *)battery->area.panel;
|
||||
int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink;
|
||||
int bat_time_height, bat_time_width, bat_time_height_ink;
|
||||
int ret = 0;
|
||||
|
||||
snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage);
|
||||
if (battery_state.state == BATTERY_FULL) {
|
||||
strcpy(buf_bat_time, "Full");
|
||||
} else {
|
||||
snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes);
|
||||
}
|
||||
get_text_size2(bat1_font_desc,
|
||||
&bat_percentage_height_ink,
|
||||
&bat_percentage_height,
|
||||
&bat_percentage_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_bat_percentage,
|
||||
strlen(buf_bat_percentage),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
get_text_size2(bat2_font_desc,
|
||||
&bat_time_height_ink,
|
||||
&bat_time_height,
|
||||
&bat_time_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_bat_time,
|
||||
strlen(buf_bat_time),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
|
||||
if (panel_horizontal) {
|
||||
int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width;
|
||||
new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area);
|
||||
if (new_size > battery->area.width || new_size < battery->area.width - 2) {
|
||||
// we try to limit the number of resize
|
||||
battery->area.width = new_size;
|
||||
battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height) / 2;
|
||||
battery->bat2_posy = battery->bat1_posy + bat_percentage_height;
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr +
|
||||
top_bottom_border_width(&battery->area);
|
||||
if (new_size > battery->area.height || new_size < battery->area.height - 2) {
|
||||
battery->area.height = new_size;
|
||||
battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height - 2) / 2;
|
||||
battery->bat2_posy = battery->bat1_posy + bat_percentage_height + 2;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
schedule_redraw(&battery->area);
|
||||
return ret;
|
||||
return resize_text_area(&battery->area,
|
||||
buf_bat_line1,
|
||||
buf_bat_line2,
|
||||
bat1_font_desc,
|
||||
bat2_font_desc,
|
||||
&battery->bat1_posy,
|
||||
&battery->bat2_posy);
|
||||
}
|
||||
|
||||
void draw_battery(void *obj, cairo_t *c)
|
||||
{
|
||||
Battery *battery = obj;
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
pango_layout_set_font_description(layout, bat1_font_desc);
|
||||
pango_layout_set_width(layout, battery->area.width * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_text(layout, buf_bat_percentage, strlen(buf_bat_percentage));
|
||||
|
||||
cairo_set_source_rgba(c,
|
||||
battery->font_color.rgb[0],
|
||||
battery->font_color.rgb[1],
|
||||
battery->font_color.rgb[2],
|
||||
battery->font_color.alpha);
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, battery->bat1_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow);
|
||||
|
||||
pango_layout_set_font_description(layout, bat2_font_desc);
|
||||
pango_layout_set_indent(layout, 0);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_text(layout, buf_bat_time, strlen(buf_bat_time));
|
||||
pango_layout_set_width(layout, battery->area.width * PANGO_SCALE);
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, battery->bat2_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow);
|
||||
pango_cairo_show_layout(c, layout);
|
||||
|
||||
g_object_unref(layout);
|
||||
Battery *battery = (Battery *)obj;
|
||||
draw_text_area(&battery->area,
|
||||
c,
|
||||
buf_bat_line1,
|
||||
buf_bat_line2,
|
||||
bat1_font_desc,
|
||||
bat2_font_desc,
|
||||
battery->bat1_posy,
|
||||
battery->bat2_posy,
|
||||
&battery->font_color);
|
||||
}
|
||||
|
||||
void battery_dump_geometry(void *obj, int indent)
|
||||
{
|
||||
Battery *battery = obj;
|
||||
fprintf(stderr, "%*sText 1: y = %d, text = %s\n", indent, "", battery->bat1_posy, buf_bat_percentage);
|
||||
fprintf(stderr, "%*sText 2: y = %d, text = %s\n", indent, "", battery->bat2_posy, buf_bat_time);
|
||||
Battery *battery = (Battery *)obj;
|
||||
fprintf(stderr, "tint2: %*sText 1: y = %d, text = %s\n", indent, "", battery->bat1_posy, buf_bat_line1);
|
||||
fprintf(stderr, "tint2: %*sText 2: y = %d, text = %s\n", indent, "", battery->bat2_posy, buf_bat_line2);
|
||||
}
|
||||
|
||||
char *battery_get_tooltip(void *obj)
|
||||
@@ -437,7 +444,7 @@ char *battery_get_tooltip(void *obj)
|
||||
return battery_os_tooltip();
|
||||
}
|
||||
|
||||
void battery_action(int button, Time time)
|
||||
void battery_action(void *obj, int button, int x, int y, Time time)
|
||||
{
|
||||
char *command = NULL;
|
||||
switch (button) {
|
||||
@@ -457,5 +464,5 @@ void battery_action(int button, Time time)
|
||||
command = battery_dwheel_command;
|
||||
break;
|
||||
}
|
||||
tint_exec(command, NULL, NULL, time);
|
||||
tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE);
|
||||
}
|
||||
|
||||
@@ -48,12 +48,15 @@ extern gboolean bat1_has_font;
|
||||
extern PangoFontDescription *bat1_font_desc;
|
||||
extern gboolean bat2_has_font;
|
||||
extern PangoFontDescription *bat2_font_desc;
|
||||
extern char *bat1_format;
|
||||
extern char *bat2_format;
|
||||
extern gboolean battery_enabled;
|
||||
extern gboolean battery_tooltip_enabled;
|
||||
extern int percentage_hide;
|
||||
|
||||
extern int8_t battery_low_status;
|
||||
extern char *battery_low_cmd;
|
||||
extern char *battery_full_cmd;
|
||||
|
||||
extern char *ac_connected_cmd;
|
||||
extern char *ac_disconnected_cmd;
|
||||
@@ -108,7 +111,7 @@ void battery_default_font_changed();
|
||||
|
||||
gboolean resize_battery(void *obj);
|
||||
|
||||
void battery_action(int button, Time time);
|
||||
void battery_action(void *obj, int button, int x, int y, Time time);
|
||||
|
||||
/* operating system specific functions */
|
||||
gboolean battery_os_init();
|
||||
|
||||
@@ -58,7 +58,7 @@ int battery_os_update(BatteryState *state)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "power update: no such sysctl");
|
||||
fprintf(stderr, "tint2: power update: no such sysctl");
|
||||
err = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ static struct uevent_notify psy_change = {UEVENT_CHANGE, "power_supply", NULL, u
|
||||
|
||||
static void uevent_battery_plug()
|
||||
{
|
||||
printf("reinitialize batteries after HW change\n");
|
||||
fprintf(stderr, "tint2: reinitialize batteries after HW change\n");
|
||||
reinit_battery();
|
||||
}
|
||||
static struct uevent_notify psy_plug = {UEVENT_ADD | UEVENT_REMOVE, "power_supply", NULL, uevent_battery_plug};
|
||||
@@ -76,7 +76,7 @@ static struct uevent_notify psy_plug = {UEVENT_ADD | UEVENT_REMOVE, "power_suppl
|
||||
#define RETURN_ON_ERROR(err) \
|
||||
if (err) { \
|
||||
g_error_free(err); \
|
||||
fprintf(stderr, RED "%s:%d: errror" RESET "\n", __FILE__, __LINE__); \
|
||||
fprintf(stderr, RED "tint2: %s:%d: errror" RESET "\n", __FILE__, __LINE__); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ static enum psy_type power_supply_get_type(const gchar *entryname)
|
||||
g_file_get_contents(path_type, &type, &typelen, &error);
|
||||
g_free(path_type);
|
||||
if (error) {
|
||||
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: %s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
g_error_free(error);
|
||||
return PSY_UNKNOWN;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ static gboolean init_linux_battery(struct psy_battery *bat)
|
||||
|
||||
bat->path_present = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "present", NULL);
|
||||
if (!g_file_test(bat->path_present, G_FILE_TEST_EXISTS)) {
|
||||
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: %s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
@@ -152,13 +152,13 @@ static gboolean init_linux_battery(struct psy_battery *bat)
|
||||
if (!g_file_test(bat->path_level_now, G_FILE_TEST_EXISTS) ||
|
||||
!g_file_test(bat->path_level_full, G_FILE_TEST_EXISTS) ||
|
||||
!g_file_test(bat->path_rate_now, G_FILE_TEST_EXISTS)) {
|
||||
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: %s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
bat->path_status = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "status", NULL);
|
||||
if (!g_file_test(bat->path_status, G_FILE_TEST_EXISTS)) {
|
||||
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: %s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ static gboolean init_linux_mains(struct psy_mains *ac)
|
||||
|
||||
ac->path_online = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "online", NULL);
|
||||
if (!g_file_test(ac->path_online, G_FILE_TEST_EXISTS)) {
|
||||
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: %s:%d: read failed" RESET "\n", __FILE__, __LINE__);
|
||||
g_free(ac->path_online);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -228,10 +228,10 @@ static void add_battery(const char *entryname)
|
||||
|
||||
if (init_linux_battery(bat)) {
|
||||
batteries = g_list_append(batteries, bat);
|
||||
fprintf(stdout, GREEN "Found battery \"%s\"" RESET "\n", bat->name);
|
||||
fprintf(stderr, GREEN "Found battery \"%s\"" RESET "\n", bat->name);
|
||||
} else {
|
||||
g_free(bat);
|
||||
fprintf(stderr, RED "Failed to initialize battery \"%s\"" RESET "\n", entryname);
|
||||
fprintf(stderr, RED "tint2: Failed to initialize battery \"%s\"" RESET "\n", entryname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,10 +242,10 @@ static void add_mains(const char *entryname)
|
||||
|
||||
if (init_linux_mains(ac)) {
|
||||
mains = g_list_append(mains, ac);
|
||||
fprintf(stdout, GREEN "Found mains \"%s\"" RESET "\n", ac->name);
|
||||
fprintf(stderr, GREEN "Found mains \"%s\"" RESET "\n", ac->name);
|
||||
} else {
|
||||
g_free(ac);
|
||||
fprintf(stderr, RED "Failed to initialize mains \"%s\"" RESET "\n", entryname);
|
||||
fprintf(stderr, RED "tint2: Failed to initialize mains \"%s\"" RESET "\n", entryname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ gboolean battery_os_init()
|
||||
RETURN_ON_ERROR(error);
|
||||
|
||||
while ((entryname = g_dir_read_name(directory))) {
|
||||
fprintf(stderr, GREEN "Found power device %s" RESET "\n", entryname);
|
||||
fprintf(stderr, GREEN "tint2: Found power device %s" RESET "\n", entryname);
|
||||
enum psy_type type = power_supply_get_type(entryname);
|
||||
|
||||
switch (type) {
|
||||
@@ -446,6 +446,17 @@ int battery_os_update(BatteryState *state)
|
||||
/* AC state */
|
||||
state->ac_connected = ac_connected;
|
||||
|
||||
if (state->state == BATTERY_UNKNOWN) {
|
||||
if (ac_connected) {
|
||||
if (total_rate_now == 0 && state->percentage >= 90)
|
||||
state->state = BATTERY_FULL;
|
||||
else
|
||||
state->state = BATTERY_CHARGING;
|
||||
} else {
|
||||
state->state = BATTERY_DISCHARGING;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ void destroy_button(void *obj)
|
||||
free_and_null(button->backend->uwheel_command);
|
||||
|
||||
if (button->backend->instances) {
|
||||
fprintf(stderr, "Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||
exit(-1);
|
||||
}
|
||||
free(button->backend);
|
||||
@@ -337,6 +337,7 @@ gboolean resize_button(void *obj)
|
||||
{
|
||||
Button *button = (Button *)obj;
|
||||
Panel *panel = (Panel *)button->area.panel;
|
||||
Area *area = &button->area;
|
||||
int horiz_padding = (panel_horizontal ? button->area.paddingxlr : button->area.paddingy);
|
||||
int vert_padding = (panel_horizontal ? button->area.paddingy : button->area.paddingxlr);
|
||||
int interior_padding = button->area.paddingx;
|
||||
@@ -360,34 +361,29 @@ gboolean resize_button(void *obj)
|
||||
if (button->frontend->icon_load_size != button->frontend->iconw)
|
||||
button_reload_icon(button);
|
||||
|
||||
int available_w, available_h;
|
||||
if (panel_horizontal) {
|
||||
available_w = panel->area.width;
|
||||
available_h = area->height - 2 * area->paddingy - left_right_border_width(area);
|
||||
} else {
|
||||
available_w =
|
||||
area->width - icon_w - (icon_w ? interior_padding : 0) - 2 * horiz_padding - left_right_border_width(area);
|
||||
available_h = panel->area.height;
|
||||
}
|
||||
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
if (button->backend->text) {
|
||||
if (panel_horizontal) {
|
||||
get_text_size2(button->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
button->backend->text,
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
} else {
|
||||
get_text_size2(button->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
button->area.width - icon_w - (icon_w ? interior_padding : 0) - 2 * horiz_padding -
|
||||
left_right_border_width(&button->area),
|
||||
button->backend->text,
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
}
|
||||
get_text_size2(button->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
available_h,
|
||||
available_w,
|
||||
button->backend->text,
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
} else {
|
||||
txt_height_ink = txt_height = txt_width = 0;
|
||||
}
|
||||
@@ -516,7 +512,6 @@ void button_dump_geometry(void *obj, int indent)
|
||||
void button_action(void *obj, int mouse_button, int x, int y, Time time)
|
||||
{
|
||||
Button *button = (Button *)obj;
|
||||
Panel *panel = (Panel *)button->area.panel;
|
||||
char *command = NULL;
|
||||
switch (mouse_button) {
|
||||
case 1:
|
||||
@@ -535,100 +530,7 @@ void button_action(void *obj, int mouse_button, int x, int y, Time time)
|
||||
command = button->backend->dwheel_command;
|
||||
break;
|
||||
}
|
||||
if (command) {
|
||||
int aligned_x, aligned_y, aligned_x1, aligned_y1, aligned_x2, aligned_y2;
|
||||
int panel_x1, panel_x2, panel_y1, panel_y2;
|
||||
if (panel_horizontal) {
|
||||
if (area_is_first(button))
|
||||
aligned_x1 = panel->posx;
|
||||
else
|
||||
aligned_x1 = panel->posx + button->area.posx;
|
||||
|
||||
if (area_is_last(button))
|
||||
aligned_x2 = panel->posx + panel->area.width;
|
||||
else
|
||||
aligned_x2 = panel->posx + button->area.posx + button->area.width;
|
||||
|
||||
if (area_is_first(button))
|
||||
aligned_x = aligned_x1;
|
||||
else if (area_is_last(button))
|
||||
aligned_x = aligned_x2;
|
||||
else
|
||||
aligned_x = aligned_x1;
|
||||
|
||||
if (panel_position & BOTTOM)
|
||||
aligned_y = panel->posy;
|
||||
else
|
||||
aligned_y = panel->posy + panel->area.height;
|
||||
|
||||
aligned_y1 = aligned_y2 = aligned_y;
|
||||
|
||||
panel_x1 = panel->posx;
|
||||
panel_x2 = panel->posx + panel->area.width;
|
||||
panel_y1 = panel_y2 = aligned_y;
|
||||
} else {
|
||||
if (area_is_first(button))
|
||||
aligned_y1 = panel->posy;
|
||||
else
|
||||
aligned_y1 = panel->posy + button->area.posy;
|
||||
|
||||
if (area_is_last(button))
|
||||
aligned_y2 = panel->posy + panel->area.height;
|
||||
else
|
||||
aligned_y2 = panel->posy + button->area.posy + button->area.height;
|
||||
|
||||
if (area_is_first(button))
|
||||
aligned_y = aligned_y1;
|
||||
else if (area_is_last(button))
|
||||
aligned_y = aligned_y2;
|
||||
else
|
||||
aligned_y = aligned_y1;
|
||||
|
||||
if (panel_position & RIGHT)
|
||||
aligned_x = panel->posx;
|
||||
else
|
||||
aligned_x = panel->posx + panel->area.width;
|
||||
|
||||
aligned_x1 = aligned_x2 = aligned_x;
|
||||
|
||||
panel_x1 = panel_x2 = aligned_x;
|
||||
panel_y1 = panel->posy;
|
||||
panel_y2 = panel->posy + panel->area.height;
|
||||
}
|
||||
|
||||
char *full_cmd = g_strdup_printf("export TINT2_BUTTON_X=%d;"
|
||||
"export TINT2_BUTTON_Y=%d;"
|
||||
"export TINT2_BUTTON_W=%d;"
|
||||
"export TINT2_BUTTON_H=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_X=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_Y=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_X1=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_Y1=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_X2=%d;"
|
||||
"export TINT2_BUTTON_ALIGNED_Y2=%d;"
|
||||
"export TINT2_BUTTON_PANEL_X1=%d;"
|
||||
"export TINT2_BUTTON_PANEL_Y1=%d;"
|
||||
"export TINT2_BUTTON_PANEL_X2=%d;"
|
||||
"export TINT2_BUTTON_PANEL_Y2=%d;"
|
||||
"%s",
|
||||
x,
|
||||
y,
|
||||
button->area.width,
|
||||
button->area.height,
|
||||
aligned_x,
|
||||
aligned_y,
|
||||
aligned_x1,
|
||||
aligned_y1,
|
||||
aligned_x2,
|
||||
aligned_y2,
|
||||
panel_x1,
|
||||
panel_y1,
|
||||
panel_x2,
|
||||
panel_y2,
|
||||
command);
|
||||
tint_exec(full_cmd, NULL, NULL, time);
|
||||
g_free(full_cmd);
|
||||
}
|
||||
tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE);
|
||||
}
|
||||
|
||||
char *button_get_tooltip(void *obj)
|
||||
|
||||
@@ -77,6 +77,9 @@ void default_clock()
|
||||
time1_font_desc = NULL;
|
||||
time2_has_font = FALSE;
|
||||
time2_font_desc = NULL;
|
||||
buf_time[0] = 0;
|
||||
buf_date[0] = 0;
|
||||
buf_tooltip[0] = 0;
|
||||
}
|
||||
|
||||
void cleanup_clock()
|
||||
@@ -111,31 +114,6 @@ void cleanup_clock()
|
||||
clock_timeout = NULL;
|
||||
}
|
||||
|
||||
void update_clocks_sec(void *arg)
|
||||
{
|
||||
gettimeofday(&time_clock, 0);
|
||||
if (time1_format) {
|
||||
for (int i = 0; i < num_panels; i++)
|
||||
panels[i].clock.area.resize_needed = 1;
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
void update_clocks_min(void *arg)
|
||||
{
|
||||
// remember old_sec because after suspend/hibernate the clock should be updated directly, and not
|
||||
// on next minute change
|
||||
time_t old_sec = time_clock.tv_sec;
|
||||
gettimeofday(&time_clock, 0);
|
||||
if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60) {
|
||||
if (time1_format) {
|
||||
for (int i = 0; i < num_panels; i++)
|
||||
panels[i].clock.area.resize_needed = 1;
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
struct tm *clock_gettime_for_tz(const char *timezone)
|
||||
{
|
||||
if (timezone) {
|
||||
@@ -152,6 +130,46 @@ struct tm *clock_gettime_for_tz(const char *timezone)
|
||||
}
|
||||
}
|
||||
|
||||
void update_clocks()
|
||||
{
|
||||
if (time1_format)
|
||||
strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone));
|
||||
if (time2_format)
|
||||
strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone));
|
||||
if (time1_format || time2_format) {
|
||||
for (int i = 0; i < num_panels; i++)
|
||||
panels[i].clock.area.resize_needed = 1;
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
int ms_until_second_change(struct timeval* tm)
|
||||
{
|
||||
long us_until_change = 1000000 - tm->tv_usec;
|
||||
// compute ms, rounding up so we don't ask to wait too short
|
||||
int ms = (us_until_change+999)/1000;
|
||||
return ms;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void update_clocks_min(void *arg)
|
||||
{
|
||||
// remember old_sec because after suspend/hibernate the clock should be updated directly, and not
|
||||
// on next minute change
|
||||
static time_t old_sec = 0;
|
||||
gettimeofday(&time_clock, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
gboolean time_format_needs_sec_ticks(char *time_format)
|
||||
{
|
||||
if (!time_format)
|
||||
@@ -170,14 +188,6 @@ void init_clock_panel(void *p)
|
||||
Panel *panel = (Panel *)p;
|
||||
Clock *clock = &panel->clock;
|
||||
|
||||
if (!clock_timeout) {
|
||||
if (time_format_needs_sec_ticks(time1_format) || time_format_needs_sec_ticks(time2_format)) {
|
||||
clock_timeout = add_timeout(10, 1000, update_clocks_sec, 0, &clock_timeout);
|
||||
} else {
|
||||
clock_timeout = add_timeout(10, 1000, update_clocks_min, 0, &clock_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (!clock->area.bg)
|
||||
clock->area.bg = &g_array_index(backgrounds, Background, 0);
|
||||
clock_init_fonts();
|
||||
@@ -205,6 +215,14 @@ void init_clock_panel(void *p)
|
||||
clock->area._get_tooltip_text = clock_get_tooltip;
|
||||
strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone));
|
||||
}
|
||||
|
||||
if (!clock_timeout) {
|
||||
if (time_format_needs_sec_ticks(time1_format) || time_format_needs_sec_ticks(time2_format)) {
|
||||
update_clocks_sec(NULL);
|
||||
} else {
|
||||
update_clocks_min(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clock_init_fonts()
|
||||
@@ -243,7 +261,7 @@ void clock_default_font_changed()
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
void clock_compute_text_geometry(Panel *panel,
|
||||
void clock_compute_text_geometry(Clock *clock,
|
||||
int *time_height_ink,
|
||||
int *time_height,
|
||||
int *time_width,
|
||||
@@ -251,139 +269,61 @@ void clock_compute_text_geometry(Panel *panel,
|
||||
int *date_height,
|
||||
int *date_width)
|
||||
{
|
||||
*date_height = *date_width = 0;
|
||||
strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone));
|
||||
get_text_size2(time1_font_desc,
|
||||
time_height_ink,
|
||||
time_height,
|
||||
time_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_time,
|
||||
strlen(buf_time),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
if (time2_format) {
|
||||
strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone));
|
||||
get_text_size2(time2_font_desc,
|
||||
date_height_ink,
|
||||
date_height,
|
||||
date_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
buf_date,
|
||||
strlen(buf_date),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
}
|
||||
area_compute_text_geometry(&clock->area,
|
||||
buf_time,
|
||||
time2_format ? buf_date : NULL,
|
||||
time1_font_desc,
|
||||
time2_font_desc,
|
||||
time_height_ink,
|
||||
time_height,
|
||||
time_width,
|
||||
date_height_ink,
|
||||
date_height,
|
||||
date_width);
|
||||
}
|
||||
|
||||
int clock_compute_desired_size(void *obj)
|
||||
{
|
||||
Clock *clock = (Clock *)obj;
|
||||
Panel *panel = (Panel *)clock->area.panel;
|
||||
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
|
||||
clock_compute_text_geometry(panel,
|
||||
&time_height_ink,
|
||||
&time_height,
|
||||
&time_width,
|
||||
&date_height_ink,
|
||||
&date_height,
|
||||
&date_width);
|
||||
|
||||
if (panel_horizontal) {
|
||||
int new_size = (time_width > date_width) ? time_width : date_width;
|
||||
new_size += 2 * clock->area.paddingxlr + left_right_border_width(&clock->area);
|
||||
return new_size;
|
||||
} else {
|
||||
int new_size = time_height + date_height + 2 * clock->area.paddingxlr + top_bottom_border_width(&clock->area);
|
||||
return new_size;
|
||||
}
|
||||
return text_area_compute_desired_size(&clock->area,
|
||||
buf_time,
|
||||
time2_format ? buf_date : NULL,
|
||||
time1_font_desc,
|
||||
time2_font_desc);
|
||||
}
|
||||
|
||||
gboolean resize_clock(void *obj)
|
||||
{
|
||||
Clock *clock = (Clock *)obj;
|
||||
Panel *panel = (Panel *)clock->area.panel;
|
||||
gboolean result = FALSE;
|
||||
|
||||
schedule_redraw(&clock->area);
|
||||
|
||||
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
|
||||
clock_compute_text_geometry(panel,
|
||||
&time_height_ink,
|
||||
&time_height,
|
||||
&time_width,
|
||||
&date_height_ink,
|
||||
&date_height,
|
||||
&date_width);
|
||||
|
||||
int new_size = clock_compute_desired_size(clock);
|
||||
if (panel_horizontal) {
|
||||
if (new_size > clock->area.width || new_size < (clock->area.width - 6)) {
|
||||
// we try to limit the number of resizes
|
||||
clock->area.width = new_size + 1;
|
||||
clock->time1_posy = (clock->area.height - time_height) / 2;
|
||||
if (time2_format) {
|
||||
clock->time1_posy -= (date_height) / 2;
|
||||
clock->time2_posy = clock->time1_posy + time_height;
|
||||
}
|
||||
result = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (new_size != clock->area.height) {
|
||||
// we try to limit the number of resizes
|
||||
clock->area.height = new_size;
|
||||
clock->time1_posy = (clock->area.height - time_height) / 2;
|
||||
if (time2_format) {
|
||||
clock->time1_posy -= (date_height) / 2;
|
||||
clock->time2_posy = clock->time1_posy + time_height;
|
||||
}
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return resize_text_area(&clock->area,
|
||||
buf_time,
|
||||
time2_format ? buf_date : NULL,
|
||||
time1_font_desc,
|
||||
time2_font_desc,
|
||||
&clock->time1_posy,
|
||||
&clock->time2_posy);
|
||||
}
|
||||
|
||||
void draw_clock(void *obj, cairo_t *c)
|
||||
{
|
||||
Clock *clock = obj;
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
|
||||
pango_layout_set_font_description(layout, time1_font_desc);
|
||||
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_text(layout, buf_time, strlen(buf_time));
|
||||
|
||||
cairo_set_source_rgba(c, clock->font.rgb[0], clock->font.rgb[1], clock->font.rgb[2], clock->font.alpha);
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, clock->time1_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
|
||||
|
||||
if (time2_format) {
|
||||
pango_layout_set_font_description(layout, time2_font_desc);
|
||||
pango_layout_set_indent(layout, 0);
|
||||
pango_layout_set_text(layout, buf_date, strlen(buf_date));
|
||||
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, clock->time2_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
|
||||
}
|
||||
|
||||
g_object_unref(layout);
|
||||
Clock *clock = (Clock *)obj;
|
||||
draw_text_area(&clock->area,
|
||||
c,
|
||||
buf_time,
|
||||
time2_format ? buf_date : NULL,
|
||||
time1_font_desc,
|
||||
time2_font_desc,
|
||||
clock->time1_posy,
|
||||
clock->time2_posy,
|
||||
&clock->font);
|
||||
}
|
||||
|
||||
void clock_dump_geometry(void *obj, int indent)
|
||||
{
|
||||
Clock *clock = (Clock *)obj;
|
||||
fprintf(stderr, "%*sText 1: y = %d, text = %s\n", indent, "", clock->time1_posy, buf_time);
|
||||
fprintf(stderr, "tint2: %*sText 1: y = %d, text = %s\n", indent, "", clock->time1_posy, buf_time);
|
||||
if (time2_format) {
|
||||
fprintf(stderr, "%*sText 2: y = %d, text = %s\n", indent, "", clock->time2_posy, buf_date);
|
||||
fprintf(stderr, "tint2: %*sText 2: y = %d, text = %s\n", indent, "", clock->time2_posy, buf_date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +333,7 @@ char *clock_get_tooltip(void *obj)
|
||||
return strdup(buf_tooltip);
|
||||
}
|
||||
|
||||
void clock_action(int button, Time time)
|
||||
void clock_action(void *obj, int button, int x, int y, Time time)
|
||||
{
|
||||
char *command = NULL;
|
||||
switch (button) {
|
||||
@@ -413,5 +353,5 @@ void clock_action(int button, Time time)
|
||||
command = clock_dwheel_command;
|
||||
break;
|
||||
}
|
||||
tint_exec(command, NULL, NULL, time);
|
||||
tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,6 @@ void draw_clock(void *obj, cairo_t *c);
|
||||
|
||||
gboolean resize_clock(void *obj);
|
||||
|
||||
void clock_action(int button, Time time);
|
||||
void clock_action(void *obj, int button, int x, int y, Time time);
|
||||
|
||||
#endif
|
||||
|
||||
140
src/config.c
140
src/config.c
@@ -119,7 +119,7 @@ void get_action(char *event, MouseAction *action)
|
||||
else if (strcmp(event, "prev_task") == 0)
|
||||
*action = PREV_TASK;
|
||||
else
|
||||
fprintf(stderr, "Error: unrecognized action '%s'. Please fix your config file.\n", event);
|
||||
fprintf(stderr, "tint2: Error: unrecognized action '%s'. Please fix your config file.\n", event);
|
||||
}
|
||||
|
||||
int get_task_status(char *status)
|
||||
@@ -135,27 +135,36 @@ int get_task_status(char *status)
|
||||
|
||||
int config_get_monitor(char *monitor)
|
||||
{
|
||||
if (strcmp(monitor, "all") != 0) {
|
||||
char *endptr;
|
||||
int ret_int = strtol(monitor, &endptr, 10);
|
||||
if (*endptr == 0)
|
||||
return ret_int - 1;
|
||||
else {
|
||||
// monitor specified by name, not by index
|
||||
int i, j;
|
||||
for (i = 0; i < server.num_monitors; ++i) {
|
||||
if (server.monitors[i].names == 0)
|
||||
// xrandr can't identify monitors
|
||||
continue;
|
||||
j = 0;
|
||||
while (server.monitors[i].names[j] != 0) {
|
||||
if (strcmp(monitor, server.monitors[i].names[j++]) == 0)
|
||||
return i;
|
||||
}
|
||||
if (strcmp(monitor, "primary") == 0) {
|
||||
for (int i = 0; i < server.num_monitors; ++i) {
|
||||
if (server.monitors[i].primary)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(monitor, "all") == 0) {
|
||||
return -1;
|
||||
}
|
||||
char *endptr;
|
||||
int ret_int = strtol(monitor, &endptr, 10);
|
||||
if (*endptr == 0)
|
||||
return ret_int - 1;
|
||||
else {
|
||||
// monitor specified by name, not by index
|
||||
int i, j;
|
||||
for (i = 0; i < server.num_monitors; ++i) {
|
||||
if (server.monitors[i].names == 0)
|
||||
// xrandr can't identify monitors
|
||||
continue;
|
||||
j = 0;
|
||||
while (server.monitors[i].names[j] != 0) {
|
||||
if (strcmp(monitor, server.monitors[i].names[j++]) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// monitor == "all" or monitor not found or xrandr can't identify monitors
|
||||
|
||||
// monitor not found or xrandr can't identify monitors => all
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -206,7 +215,7 @@ void load_launcher_app_dir(const char *path)
|
||||
Separator *get_or_create_last_separator()
|
||||
{
|
||||
if (!panel_config.separator_list) {
|
||||
fprintf(stderr, "Warning: separator items should shart with 'separator = new'\n");
|
||||
fprintf(stderr, "tint2: Warning: separator items should shart with 'separator = new'\n");
|
||||
panel_config.separator_list = g_list_append(panel_config.separator_list, create_separator());
|
||||
}
|
||||
return (Separator *)g_list_last(panel_config.separator_list)->data;
|
||||
@@ -215,7 +224,7 @@ Separator *get_or_create_last_separator()
|
||||
Execp *get_or_create_last_execp()
|
||||
{
|
||||
if (!panel_config.execp_list) {
|
||||
fprintf(stderr, "Warning: execp items should start with 'execp = new'\n");
|
||||
fprintf(stderr, "tint2: Warning: execp items should start with 'execp = new'\n");
|
||||
panel_config.execp_list = g_list_append(panel_config.execp_list, create_execp());
|
||||
}
|
||||
return (Execp *)g_list_last(panel_config.execp_list)->data;
|
||||
@@ -224,7 +233,7 @@ Execp *get_or_create_last_execp()
|
||||
Button *get_or_create_last_button()
|
||||
{
|
||||
if (!panel_config.button_list) {
|
||||
fprintf(stderr, "Warning: button items should start with 'button = new'\n");
|
||||
fprintf(stderr, "tint2: Warning: button items should start with 'button = new'\n");
|
||||
panel_config.button_list = g_list_append(panel_config.button_list, create_button());
|
||||
}
|
||||
return (Button *)g_list_last(panel_config.button_list)->data;
|
||||
@@ -381,8 +390,6 @@ void add_entry(char *key, char *value)
|
||||
/* Panel */
|
||||
else if (strcmp(key, "panel_monitor") == 0) {
|
||||
panel_config.monitor = config_get_monitor(value);
|
||||
} else if (strcmp(key, "primary_monitor_first") == 0) {
|
||||
primary_monitor_first = atoi(value);
|
||||
} else if (strcmp(key, "panel_shrink") == 0) {
|
||||
panel_shrink = atoi(value);
|
||||
} else if (strcmp(key, "panel_size") == 0) {
|
||||
@@ -408,6 +415,7 @@ void add_entry(char *key, char *value)
|
||||
}
|
||||
} else if (strcmp(key, "panel_items") == 0) {
|
||||
new_config_file = TRUE;
|
||||
free_and_null(panel_items_order);
|
||||
panel_items_order = strdup(value);
|
||||
systray_enabled = 0;
|
||||
launcher_enabled = 0;
|
||||
@@ -425,7 +433,7 @@ void add_entry(char *key, char *value)
|
||||
#ifdef ENABLE_BATTERY
|
||||
battery_enabled = 1;
|
||||
#else
|
||||
fprintf(stderr, "tint2 is build without battery support\n");
|
||||
fprintf(stderr, "tint2: tint2 has been compiled without battery support\n");
|
||||
#endif
|
||||
}
|
||||
if (panel_items_order[j] == 'S') {
|
||||
@@ -544,6 +552,11 @@ void add_entry(char *key, char *value)
|
||||
#ifdef ENABLE_BATTERY
|
||||
if (strlen(value) > 0)
|
||||
battery_low_cmd = strdup(value);
|
||||
#endif
|
||||
} else if (strcmp(key, "battery_full_cmd") == 0) {
|
||||
#ifdef ENABLE_BATTERY
|
||||
if (strlen(value) > 0)
|
||||
battery_full_cmd = strdup(value);
|
||||
#endif
|
||||
} else if (strcmp(key, "ac_connected_cmd") == 0) {
|
||||
#ifdef ENABLE_BATTERY
|
||||
@@ -564,6 +577,21 @@ void add_entry(char *key, char *value)
|
||||
#ifdef ENABLE_BATTERY
|
||||
bat2_font_desc = pango_font_description_from_string(value);
|
||||
bat2_has_font = TRUE;
|
||||
#endif
|
||||
} else if (strcmp(key, "bat1_format") == 0) {
|
||||
#ifdef ENABLE_BATTERY
|
||||
if (strlen(value) > 0) {
|
||||
free(bat1_format);
|
||||
bat1_format = strdup(value);
|
||||
battery_enabled = 1;
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(key, "bat2_format") == 0) {
|
||||
#ifdef ENABLE_BATTERY
|
||||
if (strlen(value) > 0) {
|
||||
free(bat2_format);
|
||||
bat2_format = strdup(value);
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(key, "battery_font_color") == 0) {
|
||||
#ifdef ENABLE_BATTERY
|
||||
@@ -626,7 +654,7 @@ void add_entry(char *key, char *value)
|
||||
else if (g_str_equal(value, "dots"))
|
||||
separator->style = SEPARATOR_DOTS;
|
||||
else
|
||||
fprintf(stderr, RED "Invalid separator_style value: %s" RESET "\n", value);
|
||||
fprintf(stderr, RED "tint2: Invalid separator_style value: %s" RESET "\n", value);
|
||||
} else if (strcmp(key, "separator_size") == 0) {
|
||||
Separator *separator = get_or_create_last_separator();
|
||||
separator->thickness = atoi(value);
|
||||
@@ -652,8 +680,8 @@ void add_entry(char *key, char *value)
|
||||
Execp *execp = get_or_create_last_execp();
|
||||
execp->backend->interval = 0;
|
||||
int v = atoi(value);
|
||||
if (v < 1) {
|
||||
fprintf(stderr, "execp_interval must be an integer >= 1\n");
|
||||
if (v < 0) {
|
||||
fprintf(stderr, "tint2: execp_interval must be an integer >= 0\n");
|
||||
} else {
|
||||
execp->backend->interval = v;
|
||||
}
|
||||
@@ -673,6 +701,7 @@ void add_entry(char *key, char *value)
|
||||
Execp *execp = get_or_create_last_execp();
|
||||
free_and_null(execp->backend->tooltip);
|
||||
execp->backend->tooltip = strdup(value);
|
||||
execp->backend->has_user_tooltip = TRUE;
|
||||
} else if (strcmp(key, "execp_font") == 0) {
|
||||
Execp *execp = get_or_create_last_execp();
|
||||
pango_font_description_free(execp->backend->font_desc);
|
||||
@@ -708,7 +737,7 @@ void add_entry(char *key, char *value)
|
||||
Execp *execp = get_or_create_last_execp();
|
||||
int v = atoi(value);
|
||||
if (v < 0) {
|
||||
fprintf(stderr, "execp_icon_w must be an integer >= 0\n");
|
||||
fprintf(stderr, "tint2: execp_icon_w must be an integer >= 0\n");
|
||||
} else {
|
||||
execp->backend->icon_w = v;
|
||||
}
|
||||
@@ -716,7 +745,7 @@ void add_entry(char *key, char *value)
|
||||
Execp *execp = get_or_create_last_execp();
|
||||
int v = atoi(value);
|
||||
if (v < 0) {
|
||||
fprintf(stderr, "execp_icon_h must be an integer >= 0\n");
|
||||
fprintf(stderr, "tint2: execp_icon_h must be an integer >= 0\n");
|
||||
} else {
|
||||
execp->backend->icon_h = v;
|
||||
}
|
||||
@@ -750,17 +779,23 @@ void add_entry(char *key, char *value)
|
||||
/* Button */
|
||||
else if (strcmp(key, "button") == 0) {
|
||||
panel_config.button_list = g_list_append(panel_config.button_list, create_button());
|
||||
} else if (strcmp(key, "button_icon") == 0 && strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
button->backend->icon_name = strdup(value);
|
||||
} else if (strcmp(key, "button_text") == 0 && strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
free_and_null(button->backend->text);
|
||||
button->backend->text = strdup(value);
|
||||
} else if (strcmp(key, "button_tooltip") == 0 && strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
free_and_null(button->backend->tooltip);
|
||||
button->backend->tooltip = strdup(value);
|
||||
} else if (strcmp(key, "button_icon") == 0) {
|
||||
if (strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
button->backend->icon_name = strdup(value);
|
||||
}
|
||||
} else if (strcmp(key, "button_text") == 0) {
|
||||
if (strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
free_and_null(button->backend->text);
|
||||
button->backend->text = strdup(value);
|
||||
}
|
||||
} else if (strcmp(key, "button_tooltip") == 0) {
|
||||
if (strlen(value)) {
|
||||
Button *button = get_or_create_last_button();
|
||||
free_and_null(button->backend->tooltip);
|
||||
button->backend->tooltip = strdup(value);
|
||||
}
|
||||
} else if (strcmp(key, "button_font") == 0) {
|
||||
Button *button = get_or_create_last_button();
|
||||
pango_font_description_free(button->backend->font_desc);
|
||||
@@ -960,6 +995,8 @@ void add_entry(char *key, char *value)
|
||||
hide_inactive_tasks = atoi(value);
|
||||
} else if (strcmp(key, "taskbar_hide_different_monitor") == 0) {
|
||||
hide_task_diff_monitor = atoi(value);
|
||||
} else if (strcmp(key, "taskbar_hide_different_desktop") == 0) {
|
||||
hide_task_diff_desktop = atoi(value);
|
||||
} else if (strcmp(key, "taskbar_hide_if_empty") == 0) {
|
||||
hide_taskbar_if_empty = atoi(value);
|
||||
} else if (strcmp(key, "taskbar_always_show_all_desktop_tasks") == 0) {
|
||||
@@ -1094,7 +1131,7 @@ void add_entry(char *key, char *value)
|
||||
systray.saturation = atoi(value2);
|
||||
systray.brightness = atoi(value3);
|
||||
} else if (strcmp(key, "systray_monitor") == 0) {
|
||||
systray_monitor = atoi(value) - 1;
|
||||
systray_monitor = MAX(0, config_get_monitor(value));
|
||||
} else if (strcmp(key, "systray_name_filter") == 0) {
|
||||
if (systray_hide_name_filter)
|
||||
free(systray_hide_name_filter);
|
||||
@@ -1250,8 +1287,13 @@ void add_entry(char *key, char *value)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
fprintf(stderr, "tint2 : invalid option \"%s\",\n upgrade tint2 or correct your config file\n", key);
|
||||
else if (strcmp(key, "primary_monitor_first") == 0) {
|
||||
fprintf(stderr,
|
||||
"tint2: deprecated config option \"%s\"\n"
|
||||
" Please see the documentation regarding the alternatives.\n",
|
||||
key);
|
||||
} else
|
||||
fprintf(stderr, "tint2: invalid option \"%s\",\n upgrade tint2 or correct your config file\n", key);
|
||||
|
||||
if (value1)
|
||||
free(value1);
|
||||
@@ -1263,6 +1305,8 @@ void add_entry(char *key, char *value)
|
||||
|
||||
gboolean config_read_file(const char *path)
|
||||
{
|
||||
fprintf(stderr, "tint2: Loading config file: %s\n", path);
|
||||
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return FALSE;
|
||||
@@ -1331,12 +1375,12 @@ gboolean config_read_default_path()
|
||||
|
||||
// copy tint2rc from system directory to user directory
|
||||
|
||||
fprintf(stderr, "tint2 warning: could not find a config file! Creating a default one.\n");
|
||||
fprintf(stderr, "tint2: could not find a config file! Creating a default one.\n");
|
||||
// According to the XDG Base Directory Specification
|
||||
// (https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.6.html)
|
||||
// if the user's config directory does not exist, we should create it with permissions set to 0700.
|
||||
if (!g_file_test(g_get_user_config_dir(), G_FILE_TEST_IS_DIR))
|
||||
g_mkdir(g_get_user_config_dir(), 0700);
|
||||
g_mkdir_with_parents(g_get_user_config_dir(), 0700);
|
||||
|
||||
gchar *path2 = 0;
|
||||
system_dirs = g_get_system_config_dirs();
|
||||
@@ -1353,7 +1397,7 @@ gboolean config_read_default_path()
|
||||
// copy file in user directory (path1)
|
||||
gchar *dir = g_build_filename(g_get_user_config_dir(), "tint2", NULL);
|
||||
if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
|
||||
g_mkdir(dir, 0700);
|
||||
g_mkdir_with_parents(dir, 0700);
|
||||
g_free(dir);
|
||||
|
||||
path1 = g_build_filename(g_get_user_config_dir(), "tint2", "tint2rc", NULL);
|
||||
@@ -1369,7 +1413,7 @@ gboolean config_read_default_path()
|
||||
// generate config file
|
||||
gchar *dir = g_build_filename(g_get_user_config_dir(), "tint2", NULL);
|
||||
if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
|
||||
g_mkdir(dir, 0700);
|
||||
g_mkdir_with_parents(dir, 0700);
|
||||
g_free(dir);
|
||||
|
||||
path1 = g_build_filename(g_get_user_config_dir(), "tint2", "tint2rc", NULL);
|
||||
|
||||
444
src/drag_and_drop.c
Normal file
444
src/drag_and_drop.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/**************************************************************************
|
||||
* Copyright (C) 2017 tint2 authors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "drag_and_drop.h"
|
||||
#include "panel.h"
|
||||
#include "server.h"
|
||||
#include "task.h"
|
||||
|
||||
// Drag and Drop state variables
|
||||
static Window dnd_source_window;
|
||||
static Window dnd_target_window;
|
||||
static int dnd_version;
|
||||
static Atom dnd_selection;
|
||||
static Atom dnd_atom;
|
||||
static int dnd_sent_request;
|
||||
static LauncherIcon *dnd_launcher_icon;
|
||||
gboolean debug_dnd = FALSE;
|
||||
|
||||
gboolean hidden_panel_shown_for_dnd;
|
||||
|
||||
// This fetches all the data from a property
|
||||
struct Property dnd_read_property(Display *disp, Window w, Atom property)
|
||||
{
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *ret = 0;
|
||||
|
||||
int read_bytes = 1024;
|
||||
|
||||
// Keep trying to read the property until there are no
|
||||
// bytes unread.
|
||||
do {
|
||||
if (ret != 0)
|
||||
XFree(ret);
|
||||
XGetWindowProperty(disp,
|
||||
w,
|
||||
property,
|
||||
0,
|
||||
read_bytes,
|
||||
False,
|
||||
AnyPropertyType,
|
||||
&actual_type,
|
||||
&actual_format,
|
||||
&nitems,
|
||||
&bytes_after,
|
||||
&ret);
|
||||
read_bytes *= 2;
|
||||
} while (bytes_after != 0);
|
||||
|
||||
if (debug_dnd)
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Property:\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Actual type: %s\n", __FILE__, __LINE__, GetAtomName(disp, actual_type));
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Actual format: %d\n", __FILE__, __LINE__, actual_format);
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Number of items: %lu\n", __FILE__, __LINE__, nitems);
|
||||
|
||||
Property p;
|
||||
p.data = ret;
|
||||
p.format = actual_format;
|
||||
p.nitems = nitems;
|
||||
p.type = actual_type;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// This function takes a list of targets which can be converted to (atom_list, nitems)
|
||||
// and a list of acceptable targets with prioritees (datatypes). It returns the highest
|
||||
// entry in datatypes which is also in atom_list: ie it finds the best match.
|
||||
Atom dnd_pick_target_from_list(Display *disp, Atom *atom_list, int nitems)
|
||||
{
|
||||
Atom to_be_requested = None;
|
||||
int i;
|
||||
for (i = 0; i < nitems; i++) {
|
||||
const char *atom_name = GetAtomName(disp, atom_list[i]);
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Type %d = %s\n", __FILE__, __LINE__, i, atom_name);
|
||||
|
||||
// See if this data type is allowed and of higher priority (closer to zero)
|
||||
// than the present one.
|
||||
if (strcasecmp(atom_name, "STRING") == 0) {
|
||||
to_be_requested = atom_list[i];
|
||||
} else if (strcasecmp(atom_name, "text/uri-list") == 0 && !to_be_requested) {
|
||||
to_be_requested = atom_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Accepting: Type %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, to_be_requested));
|
||||
|
||||
return to_be_requested;
|
||||
}
|
||||
|
||||
// Finds the best target given up to three atoms provided (any can be None).
|
||||
// Useful for part of the Xdnd protocol.
|
||||
Atom dnd_pick_target_from_atoms(Display *disp, Atom t1, Atom t2, Atom t3)
|
||||
{
|
||||
Atom atoms[3];
|
||||
int n = 0;
|
||||
|
||||
if (t1 != None)
|
||||
atoms[n++] = t1;
|
||||
|
||||
if (t2 != None)
|
||||
atoms[n++] = t2;
|
||||
|
||||
if (t3 != None)
|
||||
atoms[n++] = t3;
|
||||
|
||||
return dnd_pick_target_from_list(disp, atoms, n);
|
||||
}
|
||||
|
||||
// Finds the best target given a local copy of a property.
|
||||
Atom dnd_pick_target_from_targets(Display *disp, Property p)
|
||||
{
|
||||
// The list of targets is a list of atoms, so it should have type XA_ATOM
|
||||
// but it may have the type TARGETS instead.
|
||||
|
||||
if ((p.type != XA_ATOM && p.type != server.atom.TARGETS) || p.format != 32) {
|
||||
// This would be really broken. Targets have to be an atom list
|
||||
// and applications should support this. Nevertheless, some
|
||||
// seem broken (MATLAB 7, for instance), so ask for STRING
|
||||
// next instead as the lowest common denominator
|
||||
return XA_STRING;
|
||||
} else {
|
||||
Atom *atom_list = (Atom *)p.data;
|
||||
|
||||
return dnd_pick_target_from_list(disp, atom_list, p.nitems);
|
||||
}
|
||||
}
|
||||
|
||||
void dnd_init()
|
||||
{
|
||||
dnd_source_window = 0;
|
||||
dnd_target_window = 0;
|
||||
dnd_version = 0;
|
||||
dnd_selection = XInternAtom(server.display, "PRIMARY", 0);
|
||||
dnd_atom = None;
|
||||
dnd_sent_request = 0;
|
||||
dnd_launcher_icon = NULL;
|
||||
hidden_panel_shown_for_dnd = FALSE;
|
||||
}
|
||||
|
||||
void handle_dnd_enter(XClientMessageEvent *e)
|
||||
{
|
||||
dnd_atom = None;
|
||||
int more_than_3 = e->data.l[1] & 1;
|
||||
dnd_source_window = e->data.l[0];
|
||||
dnd_version = (e->data.l[1] >> 24);
|
||||
|
||||
if (debug_dnd) {
|
||||
fprintf(stderr, "tint2: DnD %s:%d: DnDEnter\n", __FILE__, __LINE__);
|
||||
fprintf(stderr,
|
||||
"DnD %s:%d: DnDEnter. Supports > 3 types = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
more_than_3 ? "yes" : "no");
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Protocol version = %d\n", __FILE__, __LINE__, dnd_version);
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Type 1 = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, e->data.l[2]));
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Type 2 = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, e->data.l[3]));
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Type 3 = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, e->data.l[4]));
|
||||
}
|
||||
|
||||
// Query which conversions are available and pick the best
|
||||
if (more_than_3) {
|
||||
// Fetch the list of possible conversions
|
||||
// Notice the similarity to TARGETS with paste.
|
||||
Property p = dnd_read_property(server.display, dnd_source_window, server.atom.XdndTypeList);
|
||||
dnd_atom = dnd_pick_target_from_targets(server.display, p);
|
||||
XFree(p.data);
|
||||
} else {
|
||||
// Use the available list
|
||||
dnd_atom = dnd_pick_target_from_atoms(server.display, e->data.l[2], e->data.l[3], e->data.l[4]);
|
||||
}
|
||||
|
||||
if (debug_dnd)
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Requested type = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, dnd_atom));
|
||||
}
|
||||
|
||||
void handle_dnd_position(XClientMessageEvent *e)
|
||||
{
|
||||
dnd_target_window = e->window;
|
||||
int accept = 0;
|
||||
Panel *panel = get_panel(e->window);
|
||||
int x, y, mapX, mapY;
|
||||
Window child;
|
||||
x = (e->data.l[2] >> 16) & 0xFFFF;
|
||||
y = e->data.l[2] & 0xFFFF;
|
||||
XTranslateCoordinates(server.display, server.root_win, e->window, x, y, &mapX, &mapY, &child);
|
||||
Task *task = click_task(panel, mapX, mapY);
|
||||
if (task) {
|
||||
if (task->desktop != server.desktop)
|
||||
change_desktop(task->desktop);
|
||||
task_handle_mouse_event(task, TOGGLE);
|
||||
} else {
|
||||
LauncherIcon *icon = click_launcher_icon(panel, mapX, mapY);
|
||||
if (icon) {
|
||||
accept = 1;
|
||||
dnd_launcher_icon = icon;
|
||||
} else {
|
||||
dnd_launcher_icon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// send XdndStatus event to get more XdndPosition events
|
||||
XClientMessageEvent se;
|
||||
se.type = ClientMessage;
|
||||
se.window = e->data.l[0];
|
||||
se.message_type = server.atom.XdndStatus;
|
||||
se.format = 32;
|
||||
se.data.l[0] = e->window; // XID of the target window
|
||||
se.data.l[1] = accept ? 1 : 0; // bit 0: accept drop bit 1: send XdndPosition events if inside rectangle
|
||||
se.data.l[2] = 0; // Rectangle x,y for which no more XdndPosition events
|
||||
se.data.l[3] = (1 << 16) | 1; // Rectangle w,h for which no more XdndPosition events
|
||||
if (accept) {
|
||||
se.data.l[4] = server.atom.XdndActionCopy;
|
||||
} else {
|
||||
se.data.l[4] = None; // None = drop will not be accepted
|
||||
}
|
||||
|
||||
if (debug_dnd)
|
||||
fprintf(stderr,
|
||||
"tint2: DnD %s:%d: Accepted: %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
accept ? GetAtomName(server.display, (Atom)se.data.l[4]) : "no");
|
||||
|
||||
XSendEvent(server.display, e->data.l[0], False, NoEventMask, (XEvent *)&se);
|
||||
}
|
||||
|
||||
void handle_dnd_drop(XClientMessageEvent *e)
|
||||
{
|
||||
if (dnd_target_window && dnd_launcher_icon) {
|
||||
if (dnd_version >= 1) {
|
||||
XConvertSelection(server.display,
|
||||
server.atom.XdndSelection,
|
||||
dnd_atom,
|
||||
dnd_selection,
|
||||
dnd_target_window,
|
||||
e->data.l[2]);
|
||||
} else {
|
||||
XConvertSelection(server.display,
|
||||
server.atom.XdndSelection,
|
||||
dnd_atom,
|
||||
dnd_selection,
|
||||
dnd_target_window,
|
||||
CurrentTime);
|
||||
}
|
||||
} else {
|
||||
// The source is sending anyway, despite instructions to the contrary.
|
||||
// So reply that we're not interested.
|
||||
XClientMessageEvent m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.type = ClientMessage;
|
||||
m.display = e->display;
|
||||
m.window = e->data.l[0];
|
||||
m.message_type = server.atom.XdndFinished;
|
||||
m.format = 32;
|
||||
m.data.l[0] = dnd_target_window;
|
||||
m.data.l[1] = 0;
|
||||
m.data.l[2] = None; // Failed.
|
||||
XSendEvent(server.display, e->data.l[0], False, NoEventMask, (XEvent *)&m);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_dnd_selection_notify(XSelectionEvent *e)
|
||||
{
|
||||
Atom target = e->target;
|
||||
|
||||
if (debug_dnd) {
|
||||
fprintf(stderr, "tint2: DnD %s:%d: A selection notify has arrived!\n", __FILE__, __LINE__);
|
||||
fprintf(stderr,
|
||||
"DnD %s:%d: Selection atom = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, e->selection));
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Target atom = %s\n", __FILE__, __LINE__, GetAtomName(server.display, target));
|
||||
fprintf(stderr,
|
||||
"DnD %s:%d: Property atom = %s\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
GetAtomName(server.display, e->property));
|
||||
}
|
||||
|
||||
if (dnd_launcher_icon) {
|
||||
Property prop = dnd_read_property(server.display, dnd_target_window, dnd_selection);
|
||||
|
||||
if (prop.data) {
|
||||
// If we're being given a list of targets (possible conversions)
|
||||
if (target == server.atom.TARGETS && !dnd_sent_request) {
|
||||
dnd_sent_request = 1;
|
||||
dnd_atom = dnd_pick_target_from_targets(server.display, prop);
|
||||
|
||||
if (dnd_atom == None) {
|
||||
if (debug_dnd)
|
||||
fprintf(stderr, "tint2: No matching datatypes.\n");
|
||||
} else {
|
||||
// Request the data type we are able to select
|
||||
if (debug_dnd)
|
||||
fprintf(stderr, "tint2: Now requsting type %s", GetAtomName(server.display, dnd_atom));
|
||||
XConvertSelection(server.display,
|
||||
dnd_selection,
|
||||
dnd_atom,
|
||||
dnd_selection,
|
||||
dnd_target_window,
|
||||
CurrentTime);
|
||||
}
|
||||
} else if (target == dnd_atom) {
|
||||
// Dump the binary data
|
||||
if (debug_dnd) {
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Received data:\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, "tint2: --------\n");
|
||||
for (int i = 0; i < prop.nitems * prop.format / 8; i++)
|
||||
fprintf(stderr, "%c", ((char *)prop.data)[i]);
|
||||
fprintf(stderr, "tint2: --------\n");
|
||||
}
|
||||
|
||||
// https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||
GString *cmd = g_string_new(dnd_launcher_icon->cmd);
|
||||
|
||||
const char *atom_name = GetAtomName(server.display, prop.type);
|
||||
if (strcasecmp(atom_name, "STRING") == 0 || strcasecmp(atom_name, "text/uri-list") == 0) {
|
||||
GString *url = g_string_new("");
|
||||
GString *prev_url = g_string_new("");
|
||||
gboolean must_unescape = strcasecmp(atom_name, "text/uri-list") == 0;
|
||||
for (int i = 0; i < prop.nitems * prop.format / 8; i++) {
|
||||
char c = ((char *)prop.data)[i];
|
||||
if (c == '\n') {
|
||||
if (must_unescape) {
|
||||
char *raw = g_uri_unescape_string(url->str, NULL);
|
||||
if (raw) {
|
||||
g_string_assign(url, raw);
|
||||
}
|
||||
free(raw);
|
||||
}
|
||||
// Many programs cannot handle this prefix
|
||||
tint2_g_string_replace(url, "file://", "");
|
||||
// Some programs put duplicates in the list, we remove them
|
||||
if (strcmp(url->str, prev_url->str) != 0) {
|
||||
if (strstr(cmd->str, "%F")) {
|
||||
GString *piece = g_string_new("");
|
||||
g_string_append(piece, " \"");
|
||||
g_string_append(piece, url->str);
|
||||
g_string_append(piece, "\"");
|
||||
g_string_append(piece, " %F");
|
||||
tint2_g_string_replace(cmd, "%F", piece->str);
|
||||
g_string_free(piece, TRUE);
|
||||
} else if (strstr(cmd->str, "%f")) {
|
||||
GString *piece = g_string_new("");
|
||||
g_string_append(piece, " \"");
|
||||
g_string_append(piece, url->str);
|
||||
g_string_append(piece, "\"");
|
||||
tint2_g_string_replace(cmd, "%f", piece->str);
|
||||
g_string_free(piece, TRUE);
|
||||
break;
|
||||
} else {
|
||||
g_string_append(cmd, " \"");
|
||||
g_string_append(cmd, url->str);
|
||||
g_string_append(cmd, "\"");
|
||||
}
|
||||
}
|
||||
g_string_assign(prev_url, url->str);
|
||||
g_string_assign(url, "");
|
||||
} else if (c == '\r') {
|
||||
// Nothing to do
|
||||
} else {
|
||||
if (c == '`' || c == '$' || c == '\\') {
|
||||
g_string_append(url, "\\");
|
||||
}
|
||||
g_string_append_c(url, c);
|
||||
}
|
||||
}
|
||||
g_string_free(url, TRUE);
|
||||
g_string_free(prev_url, TRUE);
|
||||
}
|
||||
tint2_g_string_replace(cmd, "%F", "");
|
||||
tint2_g_string_replace(cmd, "%f", "");
|
||||
if (debug_dnd)
|
||||
fprintf(stderr, "tint2: DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd->str);
|
||||
tint_exec(cmd->str,
|
||||
NULL,
|
||||
NULL,
|
||||
e->time,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
dnd_launcher_icon->start_in_terminal,
|
||||
dnd_launcher_icon->startup_notification);
|
||||
g_string_free(cmd, TRUE);
|
||||
|
||||
// Reply OK.
|
||||
XClientMessageEvent m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.type = ClientMessage;
|
||||
m.display = server.display;
|
||||
m.window = dnd_source_window;
|
||||
m.message_type = server.atom.XdndFinished;
|
||||
m.format = 32;
|
||||
m.data.l[0] = dnd_target_window;
|
||||
m.data.l[1] = 1;
|
||||
m.data.l[2] = server.atom.XdndActionCopy; // We only ever copy.
|
||||
XSendEvent(server.display, dnd_source_window, False, NoEventMask, (XEvent *)&m);
|
||||
XSync(server.display, False);
|
||||
}
|
||||
|
||||
XFree(prop.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/drag_and_drop.h
Normal file
22
src/drag_and_drop.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**************************************************************************
|
||||
* Copyright (C) 2017 tint2 authors
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DRAG_AND_DROP_H
|
||||
#define DRAG_AND_DROP_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
extern gboolean hidden_panel_shown_for_dnd;
|
||||
extern gboolean debug_dnd;
|
||||
|
||||
void dnd_init();
|
||||
|
||||
void handle_dnd_enter(XClientMessageEvent *e);
|
||||
void handle_dnd_position(XClientMessageEvent *e);
|
||||
void handle_dnd_drop(XClientMessageEvent *e);
|
||||
void handle_dnd_selection_notify(XSelectionEvent *e);
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "timer.h"
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_TOOLTIP_LEN 4096
|
||||
|
||||
void execp_timer_callback(void *arg);
|
||||
char *execp_get_tooltip(void *obj);
|
||||
void execp_init_fonts();
|
||||
@@ -30,9 +32,10 @@ void default_execp()
|
||||
|
||||
Execp *create_execp()
|
||||
{
|
||||
Execp *execp = calloc(1, sizeof(Execp));
|
||||
execp->backend = calloc(1, sizeof(ExecpBackend));
|
||||
execp->backend->child_pipe = -1;
|
||||
Execp *execp = (Execp *)calloc(1, sizeof(Execp));
|
||||
execp->backend = (ExecpBackend *)calloc(1, sizeof(ExecpBackend));
|
||||
execp->backend->child_pipe_stdout = -1;
|
||||
execp->backend->child_pipe_stderr = -1;
|
||||
execp->backend->cmd_pids = g_tree_new(cmp_ptr);
|
||||
execp->backend->interval = 30;
|
||||
execp->backend->cache_icon = TRUE;
|
||||
@@ -45,10 +48,10 @@ gpointer create_execp_frontend(gconstpointer arg, gpointer data)
|
||||
{
|
||||
Execp *execp_backend = (Execp *)arg;
|
||||
|
||||
Execp *execp_frontend = calloc(1, sizeof(Execp));
|
||||
Execp *execp_frontend = (Execp *)calloc(1, sizeof(Execp));
|
||||
execp_frontend->backend = execp_backend->backend;
|
||||
execp_backend->backend->instances = g_list_append(execp_backend->backend->instances, execp_frontend);
|
||||
execp_frontend->frontend = calloc(1, sizeof(ExecpFrontend));
|
||||
execp_frontend->frontend = (ExecpFrontend *)calloc(1, sizeof(ExecpFrontend));
|
||||
return execp_frontend;
|
||||
}
|
||||
|
||||
@@ -72,16 +75,21 @@ void destroy_execp(void *obj)
|
||||
imlib_free_image();
|
||||
execp->backend->icon = NULL;
|
||||
}
|
||||
free_and_null(execp->backend->buf_output);
|
||||
free_and_null(execp->backend->buf_stdout);
|
||||
free_and_null(execp->backend->buf_stderr);
|
||||
free_and_null(execp->backend->text);
|
||||
free_and_null(execp->backend->icon_path);
|
||||
if (execp->backend->child) {
|
||||
kill(-execp->backend->child, SIGHUP);
|
||||
execp->backend->child = 0;
|
||||
}
|
||||
if (execp->backend->child_pipe >= 0) {
|
||||
close(execp->backend->child_pipe);
|
||||
execp->backend->child_pipe = -1;
|
||||
if (execp->backend->child_pipe_stdout >= 0) {
|
||||
close(execp->backend->child_pipe_stdout);
|
||||
execp->backend->child_pipe_stdout = -1;
|
||||
}
|
||||
if (execp->backend->child_pipe_stderr >= 0) {
|
||||
close(execp->backend->child_pipe_stderr);
|
||||
execp->backend->child_pipe_stderr = -1;
|
||||
}
|
||||
if (execp->backend->cmd_pids) {
|
||||
g_tree_destroy(execp->backend->cmd_pids);
|
||||
@@ -100,7 +108,7 @@ void destroy_execp(void *obj)
|
||||
free_and_null(execp->backend->uwheel_command);
|
||||
|
||||
if (execp->backend->instances) {
|
||||
fprintf(stderr, "Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||
exit(-1);
|
||||
}
|
||||
free(execp->backend);
|
||||
@@ -138,9 +146,11 @@ void init_execp()
|
||||
// Set missing config options
|
||||
if (!execp->backend->bg)
|
||||
execp->backend->bg = &g_array_index(backgrounds, Background, 0);
|
||||
execp->backend->buf_capacity = 1024;
|
||||
execp->backend->buf_output = calloc(execp->backend->buf_capacity, 1);
|
||||
execp->backend->text = strdup(" ");
|
||||
execp->backend->buf_stdout_capacity = 1024;
|
||||
execp->backend->buf_stdout = calloc(execp->backend->buf_stdout_capacity, 1);
|
||||
execp->backend->buf_stderr_capacity = 1024;
|
||||
execp->backend->buf_stderr = calloc(execp->backend->buf_stderr_capacity, 1);
|
||||
execp->backend->text = strdup("");
|
||||
execp->backend->icon_path = NULL;
|
||||
}
|
||||
}
|
||||
@@ -186,8 +196,9 @@ void init_execp_panel(void *p)
|
||||
execp->area.on_screen = TRUE;
|
||||
instantiate_area_gradients(&execp->area);
|
||||
|
||||
if (!execp->backend->timer)
|
||||
execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer);
|
||||
execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer);
|
||||
|
||||
execp_update_post_read(execp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,156 +301,140 @@ gboolean reload_icon(Execp *execp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int execp_compute_desired_size(void *obj)
|
||||
void execp_compute_icon_text_geometry(Execp *execp,
|
||||
int *horiz_padding,
|
||||
int *vert_padding,
|
||||
int *interior_padding,
|
||||
int *icon_w,
|
||||
int *icon_h,
|
||||
gboolean *text_next_line,
|
||||
int *txt_height_ink,
|
||||
int *txt_height,
|
||||
int *txt_width,
|
||||
int *new_size,
|
||||
gboolean *resized)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
Panel *panel = (Panel *)execp->area.panel;
|
||||
int horiz_padding = (panel_horizontal ? execp->area.paddingxlr : execp->area.paddingy);
|
||||
int vert_padding = (panel_horizontal ? execp->area.paddingy : execp->area.paddingxlr);
|
||||
int interior_padding = execp->area.paddingx;
|
||||
Area *area = &execp->area;
|
||||
*horiz_padding = (panel_horizontal ? area->paddingxlr : area->paddingy);
|
||||
*vert_padding = (panel_horizontal ? area->paddingy : area->paddingxlr);
|
||||
*interior_padding = area->paddingx;
|
||||
|
||||
int icon_w, icon_h;
|
||||
if (reload_icon(execp)) {
|
||||
if (execp->backend->icon) {
|
||||
imlib_context_set_image(execp->backend->icon);
|
||||
icon_w = imlib_image_get_width();
|
||||
icon_h = imlib_image_get_height();
|
||||
*icon_w = imlib_image_get_width();
|
||||
*icon_h = imlib_image_get_height();
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
*icon_w = *icon_h = 0;
|
||||
}
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
*icon_w = *icon_h = 0;
|
||||
}
|
||||
|
||||
int text_next_line = !panel_horizontal && icon_w > execp->area.width / 2;
|
||||
*text_next_line = !panel_horizontal && *icon_w > area->width / 2;
|
||||
|
||||
int available_w, available_h;
|
||||
if (panel_horizontal) {
|
||||
available_w = panel->area.width;
|
||||
available_h = area->height - 2 * area->paddingy - left_right_border_width(area);
|
||||
} else {
|
||||
available_w = !text_next_line
|
||||
? area->width - *icon_w - (*icon_w ? *interior_padding : 0) - 2 * *horiz_padding -
|
||||
left_right_border_width(area)
|
||||
: area->width - 2 * *horiz_padding - left_right_border_width(area);
|
||||
available_h = panel->area.height;
|
||||
}
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
txt_height_ink,
|
||||
txt_height,
|
||||
txt_width,
|
||||
available_h,
|
||||
available_w,
|
||||
execp->backend->text,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
|
||||
*resized = FALSE;
|
||||
if (panel_horizontal) {
|
||||
*new_size = *txt_width;
|
||||
if (*icon_w)
|
||||
*new_size += *interior_padding + *icon_w;
|
||||
*new_size += 2 * *horiz_padding + left_right_border_width(area);
|
||||
if (*new_size < area->width && abs(*new_size - area->width) < 6) {
|
||||
// we try to limit the number of resizes
|
||||
*new_size = area->width;
|
||||
*resized = TRUE;
|
||||
} else {
|
||||
*resized = *new_size != area->width;
|
||||
}
|
||||
} else {
|
||||
if (!*text_next_line) {
|
||||
*new_size = *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
*new_size = MAX(*new_size, *icon_h + 2 * *vert_padding + top_bottom_border_width(area));
|
||||
} else {
|
||||
*new_size = *icon_h + *interior_padding + *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
}
|
||||
if (*new_size != area->height) {
|
||||
*resized = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int execp_compute_desired_size(void *obj)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
int horiz_padding, vert_padding, interior_padding;
|
||||
int icon_w, icon_h;
|
||||
gboolean text_next_line;
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
if (panel_horizontal) {
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
execp->backend->text,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
} else {
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
!text_next_line
|
||||
? execp->area.width - icon_w - (icon_w ? interior_padding : 0) - 2 * horiz_padding -
|
||||
left_right_border_width(&execp->area)
|
||||
: execp->area.width - 2 * horiz_padding - left_right_border_width(&execp->area),
|
||||
execp->backend->text,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
}
|
||||
int new_size;
|
||||
gboolean resized;
|
||||
execp_compute_icon_text_geometry(execp,
|
||||
&horiz_padding,
|
||||
&vert_padding,
|
||||
&interior_padding,
|
||||
&icon_w,
|
||||
&icon_h,
|
||||
&text_next_line,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
&new_size,
|
||||
&resized);
|
||||
|
||||
if (panel_horizontal) {
|
||||
int new_size = txt_width;
|
||||
if (icon_w)
|
||||
new_size += interior_padding + icon_w;
|
||||
new_size += 2 * horiz_padding + left_right_border_width(&execp->area);
|
||||
return new_size;
|
||||
} else {
|
||||
int new_size;
|
||||
if (!text_next_line) {
|
||||
new_size = txt_height + 2 * vert_padding + top_bottom_border_width(&execp->area);
|
||||
new_size = MAX(new_size, icon_h + 2 * vert_padding + top_bottom_border_width(&execp->area));
|
||||
} else {
|
||||
new_size =
|
||||
icon_h + interior_padding + txt_height + 2 * vert_padding + top_bottom_border_width(&execp->area);
|
||||
}
|
||||
return new_size;
|
||||
}
|
||||
return new_size;
|
||||
}
|
||||
|
||||
gboolean resize_execp(void *obj)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
Panel *panel = (Panel *)execp->area.panel;
|
||||
int horiz_padding = (panel_horizontal ? execp->area.paddingxlr : execp->area.paddingy);
|
||||
int vert_padding = (panel_horizontal ? execp->area.paddingy : execp->area.paddingxlr);
|
||||
int interior_padding = execp->area.paddingx;
|
||||
|
||||
int horiz_padding, vert_padding, interior_padding;
|
||||
int icon_w, icon_h;
|
||||
if (reload_icon(execp)) {
|
||||
if (execp->backend->icon) {
|
||||
imlib_context_set_image(execp->backend->icon);
|
||||
icon_w = imlib_image_get_width();
|
||||
icon_h = imlib_image_get_height();
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
}
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
}
|
||||
|
||||
int text_next_line = !panel_horizontal && icon_w > execp->area.width / 2;
|
||||
|
||||
gboolean text_next_line;
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
if (panel_horizontal) {
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
panel->area.width,
|
||||
execp->backend->text,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
} else {
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
!text_next_line
|
||||
? execp->area.width - icon_w - (icon_w ? interior_padding : 0) - 2 * horiz_padding -
|
||||
left_right_border_width(&execp->area)
|
||||
: execp->area.width - 2 * horiz_padding - left_right_border_width(&execp->area),
|
||||
execp->backend->text,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
}
|
||||
int new_size;
|
||||
gboolean resized;
|
||||
execp_compute_icon_text_geometry(execp,
|
||||
&horiz_padding,
|
||||
&vert_padding,
|
||||
&interior_padding,
|
||||
&icon_w,
|
||||
&icon_h,
|
||||
&text_next_line,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
&new_size,
|
||||
&resized);
|
||||
|
||||
if (panel_horizontal)
|
||||
execp->area.width = new_size;
|
||||
else
|
||||
execp->area.height = new_size;
|
||||
|
||||
gboolean result = FALSE;
|
||||
if (panel_horizontal) {
|
||||
int new_size = txt_width;
|
||||
if (icon_w)
|
||||
new_size += interior_padding + icon_w;
|
||||
new_size += 2 * horiz_padding + left_right_border_width(&execp->area);
|
||||
if (new_size > execp->area.width || new_size < (execp->area.width - 6)) {
|
||||
// we try to limit the number of resize
|
||||
execp->area.width = new_size + 1;
|
||||
result = TRUE;
|
||||
}
|
||||
} else {
|
||||
int new_size;
|
||||
if (!text_next_line) {
|
||||
new_size = txt_height + 2 * vert_padding + top_bottom_border_width(&execp->area);
|
||||
new_size = MAX(new_size, icon_h + 2 * vert_padding + top_bottom_border_width(&execp->area));
|
||||
} else {
|
||||
new_size =
|
||||
icon_h + interior_padding + txt_height + 2 * vert_padding + top_bottom_border_width(&execp->area);
|
||||
}
|
||||
if (new_size != execp->area.height) {
|
||||
execp->area.height = new_size;
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
execp->frontend->textw = txt_width;
|
||||
execp->frontend->texth = txt_height;
|
||||
if (execp->backend->centered) {
|
||||
@@ -479,13 +474,12 @@ gboolean resize_execp(void *obj)
|
||||
}
|
||||
|
||||
schedule_redraw(&execp->area);
|
||||
|
||||
return result;
|
||||
return resized;
|
||||
}
|
||||
|
||||
void draw_execp(void *obj, cairo_t *c)
|
||||
{
|
||||
Execp *execp = obj;
|
||||
Execp *execp = (Execp *)obj;
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
|
||||
if (execp->backend->has_icon && execp->backend->icon) {
|
||||
@@ -518,7 +512,7 @@ void draw_execp(void *obj, cairo_t *c)
|
||||
|
||||
void execp_dump_geometry(void *obj, int indent)
|
||||
{
|
||||
Execp *execp = obj;
|
||||
Execp *execp = (Execp *)obj;
|
||||
|
||||
if (execp->backend->has_icon && execp->backend->icon) {
|
||||
Imlib_Image tmp = imlib_context_get_image();
|
||||
@@ -547,7 +541,7 @@ void execp_dump_geometry(void *obj, int indent)
|
||||
|
||||
void execp_force_update(Execp *execp)
|
||||
{
|
||||
if (execp->backend->child_pipe > 0) {
|
||||
if (execp->backend->child_pipe_stdout > 0) {
|
||||
// Command currently running, nothing to do
|
||||
} else {
|
||||
if (execp->backend->timer)
|
||||
@@ -559,7 +553,7 @@ void execp_force_update(Execp *execp)
|
||||
|
||||
void execp_action(void *obj, int button, int x, int y, Time time)
|
||||
{
|
||||
Execp *execp = obj;
|
||||
Execp *execp = (Execp *)obj;
|
||||
char *command = NULL;
|
||||
switch (button) {
|
||||
case 1:
|
||||
@@ -579,17 +573,17 @@ void execp_action(void *obj, int button, int x, int y, Time time)
|
||||
break;
|
||||
}
|
||||
if (command) {
|
||||
char *full_cmd = g_strdup_printf("export EXECP_X=%d;"
|
||||
"export EXECP_Y=%d;"
|
||||
"export EXECP_W=%d;"
|
||||
"export EXECP_H=%d; %s",
|
||||
x,
|
||||
y,
|
||||
execp->area.width,
|
||||
execp->area.height,
|
||||
command);
|
||||
tint_exec(full_cmd, NULL, NULL, time);
|
||||
g_free(full_cmd);
|
||||
setenvd("EXECP_X", x);
|
||||
setenvd("EXECP_Y", y);
|
||||
setenvd("EXECP_W", execp->area.width);
|
||||
setenvd("EXECP_H", execp->area.height);
|
||||
pid_t pid = tint_exec(command, NULL, NULL, time, obj, x, y, FALSE, TRUE);
|
||||
unsetenv("EXECP_X");
|
||||
unsetenv("EXECP_Y");
|
||||
unsetenv("EXECP_W");
|
||||
unsetenv("EXECP_H");
|
||||
if (pid > 0)
|
||||
g_tree_insert(execp->backend->cmd_pids, GINT_TO_POINTER(pid), GINT_TO_POINTER(1));
|
||||
} else {
|
||||
execp_force_update(execp);
|
||||
}
|
||||
@@ -603,78 +597,93 @@ void execp_cmd_completed(Execp *execp, pid_t pid)
|
||||
|
||||
void execp_timer_callback(void *arg)
|
||||
{
|
||||
Execp *execp = arg;
|
||||
Execp *execp = (Execp *)arg;
|
||||
|
||||
if (!execp->backend->command)
|
||||
return;
|
||||
|
||||
// Still running!
|
||||
if (execp->backend->child_pipe > 0)
|
||||
if (execp->backend->child_pipe_stdout > 0)
|
||||
return;
|
||||
|
||||
int pipe_fd[2];
|
||||
if (pipe(pipe_fd)) {
|
||||
int pipe_fd_stdout[2];
|
||||
if (pipe(pipe_fd_stdout)) {
|
||||
// TODO maybe write this in tooltip, but if this happens we're screwed anyways
|
||||
fprintf(stderr, "Execp: Creating pipe failed!\n");
|
||||
fprintf(stderr, "tint2: Execp: Creating pipe failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK | fcntl(pipe_fd[0], F_GETFL));
|
||||
fcntl(pipe_fd_stdout[0], F_SETFL, O_NONBLOCK | fcntl(pipe_fd_stdout[0], F_GETFL));
|
||||
|
||||
int pipe_fd_stderr[2];
|
||||
if (pipe(pipe_fd_stderr)) {
|
||||
close(pipe_fd_stdout[1]);
|
||||
close(pipe_fd_stdout[0]);
|
||||
// TODO maybe write this in tooltip, but if this happens we're screwed anyways
|
||||
fprintf(stderr, "tint2: Execp: Creating pipe failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fcntl(pipe_fd_stderr[0], F_SETFL, O_NONBLOCK | fcntl(pipe_fd_stderr[0], F_GETFL));
|
||||
|
||||
// Fork and run command, capturing stdout in pipe
|
||||
pid_t child = fork();
|
||||
if (child == -1) {
|
||||
// TODO maybe write this in tooltip, but if this happens we're screwed anyways
|
||||
fprintf(stderr, "Fork failed.\n");
|
||||
close(pipe_fd[1]);
|
||||
close(pipe_fd[0]);
|
||||
fprintf(stderr, "tint2: Fork failed.\n");
|
||||
close(pipe_fd_stdout[1]);
|
||||
close(pipe_fd_stdout[0]);
|
||||
close(pipe_fd_stderr[1]);
|
||||
close(pipe_fd_stderr[0]);
|
||||
return;
|
||||
} else if (child == 0) {
|
||||
fprintf(stderr, "Executing: %s\n", execp->backend->command);
|
||||
fprintf(stderr, "tint2: Executing: %s\n", execp->backend->command);
|
||||
// We are in the child
|
||||
close(pipe_fd[0]);
|
||||
dup2(pipe_fd[1], 1); // 1 is stdout
|
||||
close(pipe_fd[1]);
|
||||
close(pipe_fd_stdout[0]);
|
||||
dup2(pipe_fd_stdout[1], 1); // 1 is stdout
|
||||
close(pipe_fd_stdout[1]);
|
||||
close(pipe_fd_stderr[0]);
|
||||
dup2(pipe_fd_stderr[1], 2); // 2 is stderr
|
||||
close(pipe_fd_stderr[1]);
|
||||
close_all_fds();
|
||||
setpgid(0, 0);
|
||||
execl("/bin/sh", "/bin/sh", "-c", execp->backend->command, NULL);
|
||||
// This should never happen!
|
||||
fprintf(stdout, "execl() failed\nexecl() failed\n");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "execl() failed\nexecl() failed\n");
|
||||
exit(0);
|
||||
}
|
||||
close(pipe_fd[1]);
|
||||
close(pipe_fd_stdout[1]);
|
||||
close(pipe_fd_stderr[1]);
|
||||
execp->backend->child = child;
|
||||
execp->backend->child_pipe = pipe_fd[0];
|
||||
execp->backend->buf_length = 0;
|
||||
execp->backend->buf_output[execp->backend->buf_length] = '\0';
|
||||
execp->backend->child_pipe_stdout = pipe_fd_stdout[0];
|
||||
execp->backend->child_pipe_stderr = pipe_fd_stderr[0];
|
||||
execp->backend->buf_stdout_length = 0;
|
||||
execp->backend->buf_stdout[execp->backend->buf_stdout_length] = '\0';
|
||||
execp->backend->buf_stderr_length = 0;
|
||||
execp->backend->buf_stderr[execp->backend->buf_stderr_length] = '\0';
|
||||
execp->backend->last_update_start_time = time(NULL);
|
||||
}
|
||||
|
||||
gboolean read_execp(void *obj)
|
||||
void read_from_pipe(int fd, char **buffer, ssize_t *buffer_length, ssize_t *buffer_capacity, gboolean *eof)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
|
||||
if (execp->backend->child_pipe < 0)
|
||||
return FALSE;
|
||||
|
||||
gboolean command_finished = FALSE;
|
||||
*eof = FALSE;
|
||||
while (1) {
|
||||
// Make sure there is free space in the buffer
|
||||
if (execp->backend->buf_capacity - execp->backend->buf_length < 1024) {
|
||||
execp->backend->buf_capacity *= 2;
|
||||
execp->backend->buf_output = realloc(execp->backend->buf_output, execp->backend->buf_capacity);
|
||||
if (*buffer_capacity - *buffer_length < 1024) {
|
||||
*buffer_capacity *= 2;
|
||||
*buffer = (char *)realloc(*buffer, *buffer_capacity);
|
||||
}
|
||||
ssize_t count = read(execp->backend->child_pipe,
|
||||
execp->backend->buf_output + execp->backend->buf_length,
|
||||
execp->backend->buf_capacity - execp->backend->buf_length - 1);
|
||||
ssize_t count = read(fd,
|
||||
*buffer + *buffer_length,
|
||||
*buffer_capacity - *buffer_length - 1);
|
||||
if (count > 0) {
|
||||
// Successful read
|
||||
execp->backend->buf_length += count;
|
||||
execp->backend->buf_output[execp->backend->buf_length] = '\0';
|
||||
*buffer_length += count;
|
||||
(*buffer)[*buffer_length] = '\0';
|
||||
continue;
|
||||
} else if (count == 0) {
|
||||
// End of file
|
||||
command_finished = TRUE;
|
||||
*eof = TRUE;
|
||||
break;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// No more data available at the moment
|
||||
@@ -684,28 +693,87 @@ gboolean read_execp(void *obj)
|
||||
continue;
|
||||
} else {
|
||||
// Error
|
||||
command_finished = TRUE;
|
||||
*eof = TRUE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean starts_with(char *s, char *prefix)
|
||||
{
|
||||
char *p, *q;
|
||||
for (p = s, q = prefix; *p && *q; p++, q++) {
|
||||
if (*p != *q)
|
||||
return FALSE;
|
||||
}
|
||||
return *q == '\0';
|
||||
}
|
||||
|
||||
char *last_substring(char *s, char *sub)
|
||||
{
|
||||
char *result = NULL;
|
||||
for (char *p = s; *p; p++) {
|
||||
if (starts_with(p, sub))
|
||||
result = p;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void rstrip(char *s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
while (len > 0) {
|
||||
if (s[len-1] == ' ' || s[len-1] == '\n') {
|
||||
s[len-1] = 0;
|
||||
len--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean read_execp(void *obj)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
|
||||
if (execp->backend->child_pipe_stdout < 0)
|
||||
return FALSE;
|
||||
|
||||
gboolean stdout_eof, stderr_eof;
|
||||
read_from_pipe(execp->backend->child_pipe_stdout,
|
||||
&execp->backend->buf_stdout,
|
||||
&execp->backend->buf_stdout_length,
|
||||
&execp->backend->buf_stdout_capacity,
|
||||
&stdout_eof);
|
||||
read_from_pipe(execp->backend->child_pipe_stderr,
|
||||
&execp->backend->buf_stderr,
|
||||
&execp->backend->buf_stderr_length,
|
||||
&execp->backend->buf_stderr_capacity,
|
||||
&stderr_eof);
|
||||
|
||||
gboolean command_finished = stdout_eof && stderr_eof;
|
||||
|
||||
if (command_finished) {
|
||||
execp->backend->child = 0;
|
||||
close(execp->backend->child_pipe);
|
||||
execp->backend->child_pipe = -1;
|
||||
close(execp->backend->child_pipe_stdout);
|
||||
execp->backend->child_pipe_stdout = -1;
|
||||
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);
|
||||
}
|
||||
|
||||
char *ansi_clear_screen = (char*)"\x1b[2J";
|
||||
if (!execp->backend->continuous && command_finished) {
|
||||
// Handle stdout
|
||||
free_and_null(execp->backend->text);
|
||||
free_and_null(execp->backend->icon_path);
|
||||
if (!execp->backend->has_icon) {
|
||||
execp->backend->text = strdup(execp->backend->buf_output);
|
||||
execp->backend->text = strdup(execp->backend->buf_stdout);
|
||||
} else {
|
||||
char *text = strchr(execp->backend->buf_output, '\n');
|
||||
char *text = strchr(execp->backend->buf_stdout, '\n');
|
||||
if (text) {
|
||||
*text = '\0';
|
||||
text++;
|
||||
@@ -713,41 +781,75 @@ gboolean read_execp(void *obj)
|
||||
} else {
|
||||
execp->backend->text = strdup("");
|
||||
}
|
||||
execp->backend->icon_path = strdup(execp->backend->buf_output);
|
||||
execp->backend->icon_path = strdup(execp->backend->buf_stdout);
|
||||
}
|
||||
int len = strlen(execp->backend->text);
|
||||
if (len > 0 && execp->backend->text[len - 1] == '\n')
|
||||
execp->backend->text[len - 1] = '\0';
|
||||
execp->backend->buf_length = 0;
|
||||
execp->backend->buf_output[execp->backend->buf_length] = '\0';
|
||||
execp->backend->buf_stdout_length = 0;
|
||||
execp->backend->buf_stdout[execp->backend->buf_stdout_length] = '\0';
|
||||
// Handle stderr
|
||||
if (!execp->backend->has_user_tooltip) {
|
||||
free_and_null(execp->backend->tooltip);
|
||||
char *start = last_substring(execp->backend->buf_stderr, ansi_clear_screen);
|
||||
if (start)
|
||||
start += strlen(ansi_clear_screen);
|
||||
else
|
||||
start = execp->backend->buf_stderr;
|
||||
if (*start) {
|
||||
execp->backend->tooltip = strdup(start);
|
||||
rstrip(execp->backend->tooltip);
|
||||
if (strlen(execp->backend->tooltip) > MAX_TOOLTIP_LEN)
|
||||
execp->backend->tooltip[MAX_TOOLTIP_LEN] = '\0';
|
||||
}
|
||||
}
|
||||
execp->backend->buf_stderr_length = 0;
|
||||
execp->backend->buf_stderr[execp->backend->buf_stderr_length] = '\0';
|
||||
//
|
||||
execp->backend->last_update_finish_time = time(NULL);
|
||||
execp->backend->last_update_duration =
|
||||
execp->backend->last_update_finish_time - execp->backend->last_update_start_time;
|
||||
return TRUE;
|
||||
} else if (execp->backend->continuous > 0) {
|
||||
// Handle stderr
|
||||
if (!execp->backend->has_user_tooltip) {
|
||||
free_and_null(execp->backend->tooltip);
|
||||
char *start = last_substring(execp->backend->buf_stderr, ansi_clear_screen);
|
||||
if (start) {
|
||||
start += strlen(ansi_clear_screen);
|
||||
memmove(execp->backend->buf_stderr, start, strlen(start) + 1);
|
||||
execp->backend->buf_stderr_length = (ssize_t)strlen(execp->backend->buf_stderr);
|
||||
}
|
||||
if (execp->backend->buf_stderr_length > MAX_TOOLTIP_LEN) {
|
||||
execp->backend->buf_stderr_length = MAX_TOOLTIP_LEN;
|
||||
execp->backend->buf_stderr[execp->backend->buf_stderr_length] = '\0';
|
||||
}
|
||||
execp->backend->tooltip = strdup(execp->backend->buf_stderr);
|
||||
rstrip(execp->backend->tooltip);
|
||||
} else {
|
||||
execp->backend->buf_stderr_length = 0;
|
||||
execp->backend->buf_stderr[execp->backend->buf_stderr_length] = '\0';
|
||||
}
|
||||
// Handle stdout
|
||||
// Count lines in buffer
|
||||
int num_lines = 0;
|
||||
char *last = execp->backend->buf_output;
|
||||
char *end = NULL;
|
||||
for (char *c = execp->backend->buf_output; *c; c++) {
|
||||
for (char *c = execp->backend->buf_stdout; *c; c++) {
|
||||
if (*c == '\n') {
|
||||
num_lines++;
|
||||
if (num_lines == execp->backend->continuous)
|
||||
end = c;
|
||||
}
|
||||
last = c;
|
||||
}
|
||||
if (*last && *last != '\n')
|
||||
num_lines++;
|
||||
if (num_lines >= execp->backend->continuous) {
|
||||
if (end)
|
||||
*end = '\0';
|
||||
free_and_null(execp->backend->text);
|
||||
free_and_null(execp->backend->icon_path);
|
||||
if (!execp->backend->has_icon) {
|
||||
execp->backend->text = strdup(execp->backend->buf_output);
|
||||
execp->backend->text = strdup(execp->backend->buf_stdout);
|
||||
} else {
|
||||
char *text = strchr(execp->backend->buf_output, '\n');
|
||||
char *text = strchr(execp->backend->buf_stdout, '\n');
|
||||
if (text) {
|
||||
*text = '\0';
|
||||
text++;
|
||||
@@ -755,23 +857,23 @@ gboolean read_execp(void *obj)
|
||||
} else {
|
||||
execp->backend->text = strdup("");
|
||||
}
|
||||
execp->backend->icon_path = strdup(execp->backend->buf_output);
|
||||
execp->backend->icon_path = strdup(execp->backend->buf_stdout);
|
||||
}
|
||||
int len = strlen(execp->backend->text);
|
||||
size_t len = strlen(execp->backend->text);
|
||||
if (len > 0 && execp->backend->text[len - 1] == '\n')
|
||||
execp->backend->text[len - 1] = '\0';
|
||||
|
||||
if (end) {
|
||||
char *next = end + 1;
|
||||
int copied = next - execp->backend->buf_output;
|
||||
int remaining = execp->backend->buf_length - copied;
|
||||
ssize_t copied = next - execp->backend->buf_stdout;
|
||||
ssize_t remaining = execp->backend->buf_stdout_length - copied;
|
||||
if (remaining > 0) {
|
||||
memmove(execp->backend->buf_output, next, remaining);
|
||||
execp->backend->buf_length = remaining;
|
||||
execp->backend->buf_output[execp->backend->buf_length] = '\0';
|
||||
memmove(execp->backend->buf_stdout, next, (size_t)remaining);
|
||||
execp->backend->buf_stdout_length = remaining;
|
||||
execp->backend->buf_stdout[execp->backend->buf_stdout_length] = '\0';
|
||||
} else {
|
||||
execp->backend->buf_length = 0;
|
||||
execp->backend->buf_output[execp->backend->buf_length] = '\0';
|
||||
execp->backend->buf_stdout_length = 0;
|
||||
execp->backend->buf_stdout[execp->backend->buf_stdout_length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,7 +908,7 @@ const char *time_to_string(int seconds, char *buffer)
|
||||
|
||||
char *execp_get_tooltip(void *obj)
|
||||
{
|
||||
Execp *execp = obj;
|
||||
Execp *execp = (Execp *)obj;
|
||||
|
||||
if (execp->backend->tooltip) {
|
||||
if (strlen(execp->backend->tooltip) > 0)
|
||||
@@ -820,7 +922,7 @@ char *execp_get_tooltip(void *obj)
|
||||
char tmp_buf1[256];
|
||||
char tmp_buf2[256];
|
||||
char tmp_buf3[256];
|
||||
if (execp->backend->child_pipe < 0) {
|
||||
if (execp->backend->child_pipe_stdout < 0) {
|
||||
// Not executing command
|
||||
if (execp->backend->last_update_finish_time) {
|
||||
// We updated at least once
|
||||
@@ -858,3 +960,44 @@ char *execp_get_tooltip(void *obj)
|
||||
}
|
||||
return strdup(execp->backend->tooltip_text);
|
||||
}
|
||||
|
||||
void execp_update_post_read(Execp *execp)
|
||||
{
|
||||
int icon_h, icon_w;
|
||||
if (reload_icon(execp)) {
|
||||
if (execp->backend->icon) {
|
||||
imlib_context_set_image(execp->backend->icon);
|
||||
icon_w = imlib_image_get_width();
|
||||
icon_h = imlib_image_get_height();
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
}
|
||||
} else {
|
||||
icon_w = icon_h = 0;
|
||||
}
|
||||
|
||||
if ((icon_h == 0 || icon_w == 0) && execp->backend->text[0] == 0) {
|
||||
// Easy to test with bash -c 'R=$(( RANDOM % 2 )); [ $R -eq 0 ] && echo HELLO $R'
|
||||
if (execp->area.on_screen)
|
||||
hide(&execp->area);
|
||||
} else {
|
||||
if (!execp->area.on_screen)
|
||||
show(&execp->area);
|
||||
execp->area.resize_needed = TRUE;
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_execp_events()
|
||||
{
|
||||
for (GList *l = panel_config.execp_list; l; l = l->next) {
|
||||
Execp *execp = (Execp *)l->data;
|
||||
if (read_execp(execp)) {
|
||||
GList *l_instance;
|
||||
for (l_instance = execp->backend->instances; l_instance; l_instance = l_instance->next) {
|
||||
Execp *instance = (Execp *)l_instance->data;
|
||||
execp_update_post_read(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef struct ExecpBackend {
|
||||
gboolean cache_icon;
|
||||
int icon_w;
|
||||
int icon_h;
|
||||
gboolean has_user_tooltip;
|
||||
char *tooltip;
|
||||
gboolean centered;
|
||||
gboolean has_font;
|
||||
@@ -46,20 +47,24 @@ typedef struct ExecpBackend {
|
||||
|
||||
// Backend state:
|
||||
timeout *timer;
|
||||
int child_pipe;
|
||||
int child_pipe_stdout;
|
||||
int child_pipe_stderr;
|
||||
pid_t child;
|
||||
|
||||
// Command output buffer
|
||||
char *buf_output;
|
||||
int buf_length;
|
||||
int buf_capacity;
|
||||
char *buf_stdout;
|
||||
ssize_t buf_stdout_length;
|
||||
ssize_t buf_stdout_capacity;
|
||||
char *buf_stderr;
|
||||
ssize_t buf_stderr_length;
|
||||
ssize_t buf_stderr_capacity;
|
||||
|
||||
// Text extracted from the output buffer
|
||||
char *text;
|
||||
// Icon path extracted from the output buffer
|
||||
char *icon_path;
|
||||
Imlib_Image icon;
|
||||
char tooltip_text[512];
|
||||
gchar tooltip_text[512];
|
||||
|
||||
// The time the last command was started
|
||||
time_t last_update_start_time;
|
||||
@@ -138,6 +143,11 @@ void execp_cmd_completed(Execp *obj, pid_t pid);
|
||||
// Returns 1 if the output has been updated and a redraw is needed.
|
||||
gboolean read_execp(void *obj);
|
||||
|
||||
// Called for Execp front elements when the command output has changed.
|
||||
void execp_update_post_read(Execp *execp);
|
||||
|
||||
void execp_default_font_changed();
|
||||
|
||||
void handle_execp_events();
|
||||
|
||||
#endif // EXECPLUGIN_H
|
||||
|
||||
286
src/init.c
Normal file
286
src/init.c
Normal file
@@ -0,0 +1,286 @@
|
||||
#include "init.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "drag_and_drop.h"
|
||||
#include "fps_distribution.h"
|
||||
#include "panel.h"
|
||||
#include "server.h"
|
||||
#include "signals.h"
|
||||
#include "tooltip.h"
|
||||
#include "tracing.h"
|
||||
#include "uevent.h"
|
||||
#include "version.h"
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
fprintf(stdout,
|
||||
"Usage: tint2 [OPTION...]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -c path_to_config_file Loads the configuration file from a\n"
|
||||
" custom location.\n"
|
||||
" -v, --version Prints version information and exits.\n"
|
||||
" -h, --help Display this help and exits.\n"
|
||||
"\n"
|
||||
"For more information, run `man tint2` or visit the project page\n"
|
||||
"<https://gitlab.com/o9000/tint2>.\n");
|
||||
}
|
||||
|
||||
void handle_cli_arguments(int argc, char **argv)
|
||||
{
|
||||
// Read command line arguments
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
gboolean error = FALSE;
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
print_usage();
|
||||
exit(0);
|
||||
} 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], "-c") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
i++;
|
||||
config_path = strdup(argv[i]);
|
||||
} else {
|
||||
error = TRUE;
|
||||
}
|
||||
} else if (strcmp(argv[i], "-s") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
i++;
|
||||
snapshot_path = strdup(argv[i]);
|
||||
} else {
|
||||
error = TRUE;
|
||||
}
|
||||
} else if (i + 1 == argc) {
|
||||
config_path = strdup(argv[i]);
|
||||
}
|
||||
#ifdef ENABLE_BATTERY
|
||||
else if (strcmp(argv[i], "--battery-sys-prefix") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
i++;
|
||||
battery_sys_prefix = strdup(argv[i]);
|
||||
} else {
|
||||
error = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
error = TRUE;
|
||||
}
|
||||
if (error) {
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_env_vars()
|
||||
{
|
||||
debug_geometry = getenv("DEBUG_GEOMETRY") != NULL;
|
||||
debug_gradients = getenv("DEBUG_GRADIENTS") != NULL;
|
||||
debug_icons = getenv("DEBUG_ICONS") != NULL;
|
||||
debug_fps = getenv("DEBUG_FPS") != NULL;
|
||||
debug_frames = getenv("DEBUG_FRAMES") != NULL;
|
||||
debug_dnd = getenv("DEBUG_DND") != NULL;
|
||||
if (debug_fps) {
|
||||
init_fps_distribution();
|
||||
char *s = getenv("TRACING_FPS_THRESHOLD");
|
||||
if (!s || sscanf(s, "%lf", &tracing_fps_threshold) != 1) {
|
||||
tracing_fps_threshold = 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static timeout *detect_compositor_timer = NULL;
|
||||
static int detect_compositor_timer_counter = 0;
|
||||
|
||||
void detect_compositor(void *arg)
|
||||
{
|
||||
if (server.composite_manager) {
|
||||
stop_timeout(detect_compositor_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
detect_compositor_timer_counter--;
|
||||
if (detect_compositor_timer_counter < 0) {
|
||||
stop_timeout(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);
|
||||
// Restart tint2
|
||||
fprintf(stderr, "tint2: Detected compositor, restarting tint2...\n");
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
||||
void start_detect_compositor()
|
||||
{
|
||||
// Already have a compositor, nothing to do
|
||||
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);
|
||||
}
|
||||
|
||||
void create_default_elements()
|
||||
{
|
||||
default_timeout();
|
||||
default_systray();
|
||||
memset(&server, 0, sizeof(server));
|
||||
#ifdef ENABLE_BATTERY
|
||||
default_battery();
|
||||
#endif
|
||||
default_clock();
|
||||
default_launcher();
|
||||
default_taskbar();
|
||||
default_tooltip();
|
||||
default_execp();
|
||||
default_button();
|
||||
default_panel();
|
||||
}
|
||||
|
||||
void init_post_config()
|
||||
{
|
||||
server_init_visual();
|
||||
server_init_xdamage();
|
||||
|
||||
imlib_context_set_display(server.display);
|
||||
imlib_context_set_visual(server.visual);
|
||||
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");
|
||||
}
|
||||
|
||||
XSync(server.display, False);
|
||||
}
|
||||
|
||||
void init_X11_pre_config()
|
||||
{
|
||||
server.display = XOpenDisplay(NULL);
|
||||
if (!server.display) {
|
||||
fprintf(stderr, "tint2: could not open display!\n");
|
||||
exit(1);
|
||||
}
|
||||
server.x11_fd = ConnectionNumber(server.display);
|
||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
||||
XSetIOErrorHandler((XIOErrorHandler)x11_io_error);
|
||||
server_init_atoms();
|
||||
server.screen = DefaultScreen(server.display);
|
||||
server.root_win = RootWindow(server.display, server.screen);
|
||||
server.desktop = get_current_desktop();
|
||||
|
||||
// Needed since the config file uses '.' as decimal separator
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "POSIX");
|
||||
|
||||
/* Catch events */
|
||||
XSelectInput(server.display, server.root_win, PropertyChangeMask | StructureNotifyMask);
|
||||
|
||||
// get monitor and desktop config
|
||||
get_monitors();
|
||||
get_desktops();
|
||||
|
||||
server.disable_transparency = 0;
|
||||
|
||||
xsettings_client = xsettings_client_new(server.display, server.screen, xsettings_notify_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
void init(int argc, char **argv)
|
||||
{
|
||||
setlinebuf(stdout);
|
||||
setlinebuf(stderr);
|
||||
default_config();
|
||||
handle_cli_arguments(argc, argv);
|
||||
create_default_elements();
|
||||
init_signals();
|
||||
handle_env_vars();
|
||||
|
||||
init_X11_pre_config();
|
||||
if (!config_read()) {
|
||||
fprintf(stderr, "tint2: Could not read config file.\n");
|
||||
print_usage();
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
init_post_config();
|
||||
start_detect_compositor();
|
||||
init_panel();
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
#ifdef HAVE_SN
|
||||
if (startup_notifications) {
|
||||
sn_display_unref(server.sn_display);
|
||||
server.sn_display = NULL;
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
|
||||
cleanup_button();
|
||||
cleanup_execp();
|
||||
cleanup_systray();
|
||||
cleanup_tooltip();
|
||||
cleanup_clock();
|
||||
cleanup_launcher();
|
||||
#ifdef ENABLE_BATTERY
|
||||
cleanup_battery();
|
||||
#endif
|
||||
cleanup_panel();
|
||||
cleanup_config();
|
||||
|
||||
if (default_icon) {
|
||||
imlib_context_set_image(default_icon);
|
||||
imlib_free_image();
|
||||
default_icon = NULL;
|
||||
}
|
||||
imlib_context_disconnect_display();
|
||||
|
||||
xsettings_client_destroy(xsettings_client);
|
||||
xsettings_client = NULL;
|
||||
|
||||
cleanup_server();
|
||||
cleanup_timeout();
|
||||
|
||||
if (server.display)
|
||||
XCloseDisplay(server.display);
|
||||
server.display = NULL;
|
||||
|
||||
if (sigchild_pipe_valid) {
|
||||
sigchild_pipe_valid = FALSE;
|
||||
close(sigchild_pipe[1]);
|
||||
close(sigchild_pipe[0]);
|
||||
}
|
||||
|
||||
uevent_cleanup();
|
||||
cleanup_fps_distribution();
|
||||
|
||||
#ifdef HAVE_TRACING
|
||||
cleanup_tracing();
|
||||
#endif
|
||||
}
|
||||
7
src/init.h
Normal file
7
src/init.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef INIT_H
|
||||
#define INIT_H
|
||||
|
||||
void init(int argc, char **argv);
|
||||
void cleanup();
|
||||
|
||||
#endif
|
||||
@@ -96,6 +96,10 @@ void expand_exec(DesktopEntry *entry, const char *path)
|
||||
q += strlen("''");
|
||||
q += strlen(path);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'f' || *p == 'F') {
|
||||
sprintf(q, "%c%c", '%', *p);
|
||||
q += 2;
|
||||
q--; // To balance the q++ in the for
|
||||
} else {
|
||||
// We don't care about other expansions
|
||||
q--; // Delete the last % from q
|
||||
@@ -113,10 +117,12 @@ gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry)
|
||||
{
|
||||
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
|
||||
entry->hidden_from_menus = FALSE;
|
||||
entry->start_in_terminal = FALSE;
|
||||
entry->startup_notification = TRUE;
|
||||
|
||||
FILE *fp = fopen(path, "rt");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Could not open file %s\n", path);
|
||||
fprintf(stderr, "tint2: Could not open file %s\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -126,14 +132,14 @@ gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry)
|
||||
int lang_index_default = 1;
|
||||
#define LANG_DBG 0
|
||||
if (LANG_DBG)
|
||||
printf("Languages:");
|
||||
fprintf(stderr, "tint2: Languages:");
|
||||
for (int i = 0; languages[i]; i++) {
|
||||
lang_index_default = i + 1;
|
||||
if (LANG_DBG)
|
||||
printf(" %s", languages[i]);
|
||||
fprintf(stderr, "tint2: %s", languages[i]);
|
||||
}
|
||||
if (LANG_DBG)
|
||||
printf("\n");
|
||||
fprintf(stderr, "tint2: \n");
|
||||
// we currently do not know about any Name key at all, so use an invalid index
|
||||
int lang_index_name = lang_index_default + 1;
|
||||
int lang_index_generic_name = lang_index_default + 1;
|
||||
@@ -192,6 +198,10 @@ gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry)
|
||||
entry->icon = strdup(value);
|
||||
} else if (strcmp(key, "NoDisplay") == 0) {
|
||||
entry->hidden_from_menus = strcasecmp(value, "true") == 0;
|
||||
} else if (strcmp(key, "Terminal") == 0) {
|
||||
entry->start_in_terminal = strcasecmp(value, "true") == 0;
|
||||
} else if (strcmp(key, "StartupNotify") == 0) {
|
||||
entry->startup_notification = strcasecmp(value, "true") == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,11 +288,11 @@ void free_desktop_entry(DesktopEntry *entry)
|
||||
|
||||
void test_read_desktop_file()
|
||||
{
|
||||
fprintf(stdout, "\033[1;33m");
|
||||
fprintf(stderr, YELLOW);
|
||||
DesktopEntry entry;
|
||||
read_desktop_file("/usr/share/applications/firefox.desktop", &entry);
|
||||
printf("Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec);
|
||||
fprintf(stdout, "\033[0m");
|
||||
fprintf(stderr, "tint2: Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec);
|
||||
fprintf(stderr, RESET);
|
||||
}
|
||||
|
||||
GSList *apps_locations = NULL;
|
||||
|
||||
@@ -17,6 +17,8 @@ typedef struct DesktopEntry {
|
||||
char *path;
|
||||
char *cwd;
|
||||
gboolean hidden_from_menus;
|
||||
gboolean start_in_terminal;
|
||||
gboolean startup_notification;
|
||||
} DesktopEntry;
|
||||
|
||||
// Parses a line of the form "key = value". Modifies the line.
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "common.h"
|
||||
#include "cache.h"
|
||||
|
||||
gboolean debug_icons = FALSE;
|
||||
|
||||
#define ICON_DIR_TYPE_SCALABLE 0
|
||||
#define ICON_DIR_TYPE_FIXED 1
|
||||
#define ICON_DIR_TYPE_THRESHOLD 2
|
||||
@@ -90,7 +92,7 @@ IconTheme *load_theme_from_index(const char *file_name, const char *name)
|
||||
size_t line_size;
|
||||
|
||||
if ((f = fopen(file_name, "rt")) == NULL) {
|
||||
fprintf(stderr, "Could not open theme '%s'\n", file_name);
|
||||
fprintf(stderr, "tint2: Could not open theme '%s'\n", file_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -325,22 +327,22 @@ void free_themes(IconThemeWrapper *wrapper)
|
||||
|
||||
void test_launcher_read_theme_file()
|
||||
{
|
||||
fprintf(stdout, "\033[1;33m");
|
||||
fprintf(stdout, YELLOW);
|
||||
IconTheme *theme = load_theme("oxygen");
|
||||
if (!theme) {
|
||||
printf("Could not load theme\n");
|
||||
fprintf(stderr, "tint2: Could not load theme\n");
|
||||
return;
|
||||
}
|
||||
printf("Loaded theme: %s\n", theme->name);
|
||||
fprintf(stderr, "tint2: Loaded theme: %s\n", theme->name);
|
||||
GSList *item = theme->list_inherits;
|
||||
while (item != NULL) {
|
||||
printf("Inherits:%s\n", (char *)item->data);
|
||||
fprintf(stderr, "tint2: Inherits:%s\n", (char *)item->data);
|
||||
item = g_slist_next(item);
|
||||
}
|
||||
item = theme->list_directories;
|
||||
while (item != NULL) {
|
||||
IconThemeDir *dir = item->data;
|
||||
printf("Dir:%s Size=%d MinSize=%d MaxSize=%d Threshold=%d Type=%s\n",
|
||||
fprintf(stderr, "tint2: Dir:%s Size=%d MinSize=%d MaxSize=%d Threshold=%d Type=%s\n",
|
||||
dir->name,
|
||||
dir->size,
|
||||
dir->min_size,
|
||||
@@ -352,7 +354,7 @@ void test_launcher_read_theme_file()
|
||||
: "?????");
|
||||
item = g_slist_next(item);
|
||||
}
|
||||
fprintf(stdout, "\033[0m");
|
||||
fprintf(stdout, RESET);
|
||||
}
|
||||
|
||||
gboolean str_list_contains(const GSList *list, const char *value)
|
||||
@@ -379,7 +381,7 @@ void load_themes_helper(const char *name, GSList **themes, GSList **queued)
|
||||
char *queued_name = queue->data;
|
||||
queue = g_slist_remove(queue, queued_name);
|
||||
|
||||
fprintf(stderr, " '%s',", queued_name);
|
||||
fprintf(stderr, "tint2: '%s',", queued_name);
|
||||
IconTheme *theme = load_theme(queued_name);
|
||||
if (theme != NULL) {
|
||||
*themes = g_slist_append(*themes, theme);
|
||||
@@ -399,7 +401,7 @@ void load_themes_helper(const char *name, GSList **themes, GSList **queued)
|
||||
|
||||
free(queued_name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "tint2: \n");
|
||||
|
||||
// Free the queue
|
||||
GSList *l;
|
||||
@@ -413,7 +415,7 @@ void load_default_theme(IconThemeWrapper *wrapper)
|
||||
if (wrapper->_themes_loaded)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Loading icon theme %s:" RESET "\n", wrapper->icon_theme_name);
|
||||
fprintf(stderr, GREEN "tint2: Loading icon theme %s:" RESET "\n", wrapper->icon_theme_name);
|
||||
|
||||
load_themes_helper(wrapper->icon_theme_name, &wrapper->themes, &wrapper->_queued);
|
||||
load_themes_helper("hicolor", &wrapper->themes, &wrapper->_queued);
|
||||
@@ -426,7 +428,7 @@ void load_fallbacks(IconThemeWrapper *wrapper)
|
||||
if (wrapper->_fallback_loaded)
|
||||
return;
|
||||
|
||||
fprintf(stderr, RED "Loading additional icon themes (this means your icon theme is incomplete)..." RESET "\n");
|
||||
fprintf(stderr, RED "tint2: Loading additional icon themes (this means your icon theme is incomplete)..." RESET "\n");
|
||||
|
||||
// Load wrapper->themes_fallback
|
||||
const GSList *location;
|
||||
@@ -459,7 +461,7 @@ void load_icon_cache(IconThemeWrapper *wrapper)
|
||||
if (wrapper->_cache.loaded)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Loading icon theme cache..." RESET "\n");
|
||||
fprintf(stderr, GREEN "tint2: Loading icon theme cache..." RESET "\n");
|
||||
|
||||
gchar *cache_path = get_icon_cache_path();
|
||||
load_cache(&wrapper->_cache, cache_path);
|
||||
@@ -471,7 +473,7 @@ void save_icon_cache(IconThemeWrapper *wrapper)
|
||||
if (!wrapper || !wrapper->_cache.dirty)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Saving icon theme cache..." RESET "\n");
|
||||
fprintf(stderr, GREEN "tint2: Saving icon theme cache..." RESET "\n");
|
||||
gchar *cache_path = get_icon_cache_path();
|
||||
save_cache(&wrapper->_cache, cache_path);
|
||||
g_free(cache_path);
|
||||
@@ -482,7 +484,7 @@ IconThemeWrapper *load_themes(const char *icon_theme_name)
|
||||
IconThemeWrapper *wrapper = calloc(1, sizeof(IconThemeWrapper));
|
||||
|
||||
if (!icon_theme_name) {
|
||||
fprintf(stderr, "Missing icon_theme_name theme, default to 'hicolor'.\n");
|
||||
fprintf(stderr, "tint2: Missing icon_theme_name theme, default to 'hicolor'.\n");
|
||||
icon_theme_name = "hicolor";
|
||||
}
|
||||
|
||||
@@ -533,7 +535,6 @@ gint compare_theme_directories(gconstpointer a, gconstpointer b, gpointer size_q
|
||||
return abs(da->size - size) - abs(db->size - size);
|
||||
}
|
||||
|
||||
#define DEBUG_ICON_SEARCH 0
|
||||
char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
{
|
||||
if (icon_name == NULL)
|
||||
@@ -585,6 +586,8 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
char *file_name = calloc(file_name_size, 1);
|
||||
|
||||
for (theme = themes; theme; theme = g_slist_next(theme)) {
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Searching theme: %s\n", ((IconTheme *)theme->data)->name);
|
||||
((IconTheme *)theme->data)->list_directories =
|
||||
g_slist_sort_with_data(((IconTheme *)theme->data)->list_directories,
|
||||
compare_theme_directories,
|
||||
@@ -600,6 +603,8 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
(!next_larger_theme ? 1 : theme == next_larger_theme));
|
||||
if (!possible)
|
||||
continue;
|
||||
if (debug_icons)
|
||||
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)) {
|
||||
@@ -617,11 +622,11 @@ 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);
|
||||
if (DEBUG_ICON_SEARCH)
|
||||
printf("checking %s\n", file_name);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Checking %s\n", file_name);
|
||||
if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
|
||||
if (DEBUG_ICON_SEARCH)
|
||||
printf("found: %s\n", file_name);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Found potential match: %s\n", file_name);
|
||||
// Closest match
|
||||
if (directory_size_distance((IconThemeDir *)dir->data, size) < minimal_size &&
|
||||
(!best_file_theme ? 1 : theme == best_file_theme)) {
|
||||
@@ -632,8 +637,8 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
best_file_name = strdup(file_name);
|
||||
minimal_size = directory_size_distance((IconThemeDir *)dir->data, size);
|
||||
best_file_theme = theme;
|
||||
if (DEBUG_ICON_SEARCH)
|
||||
printf("best_file_name = %s; minimal_size = %d\n", best_file_name, minimal_size);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: best_file_name = %s; minimal_size = %d\n", best_file_name, minimal_size);
|
||||
}
|
||||
// Next larger match
|
||||
if (((IconThemeDir *)dir->data)->size >= size &&
|
||||
@@ -646,8 +651,8 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
next_larger = strdup(file_name);
|
||||
next_larger_size = ((IconThemeDir *)dir->data)->size;
|
||||
next_larger_theme = theme;
|
||||
if (DEBUG_ICON_SEARCH)
|
||||
printf("next_larger = %s; next_larger_size = %d\n", next_larger, next_larger_size);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: next_larger = %s; next_larger_size = %d\n", next_larger, next_larger_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -668,6 +673,8 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
|
||||
// Look in unthemed icons
|
||||
{
|
||||
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)) {
|
||||
char *base_name = (char *)base->data;
|
||||
@@ -675,9 +682,11 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
file_name = calloc(strlen(base_name) + strlen(icon_name) + strlen(extension) + 100, 1);
|
||||
// filename = directory/iconname.extension
|
||||
sprintf(file_name, "%s/%s%s", base_name, icon_name, extension);
|
||||
if (DEBUG_ICON_SEARCH)
|
||||
printf("checking %s\n", file_name);
|
||||
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 {
|
||||
@@ -715,7 +724,7 @@ char *get_icon_path_from_cache(IconThemeWrapper *wrapper, const char *icon_name,
|
||||
if (!g_file_test(value, G_FILE_TEST_EXISTS))
|
||||
return NULL;
|
||||
|
||||
// fprintf(stderr, "Icon path found in cache: theme = %s, icon = %s, size = %d, path = %s\n",
|
||||
// fprintf(stderr, "tint2: Icon path found in cache: theme = %s, icon = %s, size = %d, path = %s\n",
|
||||
// wrapper->icon_theme_name, icon_name, size, value);
|
||||
|
||||
return strdup(value);
|
||||
@@ -742,28 +751,44 @@ void add_icon_path_to_cache(IconThemeWrapper *wrapper, const char *icon_name, in
|
||||
|
||||
char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size, gboolean use_fallbacks)
|
||||
{
|
||||
if (!wrapper)
|
||||
if (debug_icons)
|
||||
fprintf(stderr,
|
||||
"Searching for icon %s with size %d, fallbacks %sallowed\n",
|
||||
icon_name,
|
||||
size,
|
||||
use_fallbacks ? "" : "not ");
|
||||
if (!wrapper) {
|
||||
if (debug_icons)
|
||||
fprintf(stderr,
|
||||
"Icon search aborted, themes not loaded\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!icon_name || strlen(icon_name) == 0)
|
||||
goto notfound;
|
||||
|
||||
char *path = get_icon_path_from_cache(wrapper, icon_name, size);
|
||||
if (path)
|
||||
if (path) {
|
||||
if (debug_icons)
|
||||
fprintf(stderr,
|
||||
"Icon found in cache: %s\n", path);
|
||||
return path;
|
||||
}
|
||||
|
||||
load_default_theme(wrapper);
|
||||
|
||||
icon_name = icon_name ? icon_name : DEFAULT_ICON;
|
||||
path = get_icon_path_helper(wrapper->themes, icon_name, size);
|
||||
if (path) {
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Icon found: %s\n", path);
|
||||
add_icon_path_to_cache(wrapper, icon_name, size, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
if (!use_fallbacks)
|
||||
goto notfound;
|
||||
fprintf(stderr, YELLOW "Icon not found in default theme: %s" RESET "\n", icon_name);
|
||||
fprintf(stderr, YELLOW "tint2: Icon not found in default theme: %s" RESET "\n", icon_name);
|
||||
load_fallbacks(wrapper);
|
||||
|
||||
path = get_icon_path_helper(wrapper->themes_fallback, icon_name, size);
|
||||
@@ -773,7 +798,7 @@ char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size,
|
||||
}
|
||||
|
||||
notfound:
|
||||
fprintf(stderr, RED "Could not find icon '%s', using default." RESET "\n", icon_name);
|
||||
fprintf(stderr, RED "tint2: Could not find icon '%s', using default." RESET "\n", icon_name);
|
||||
path = get_icon_path_helper(wrapper->themes, DEFAULT_ICON, size);
|
||||
if (path)
|
||||
return path;
|
||||
|
||||
@@ -57,4 +57,6 @@ char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size,
|
||||
// Do not free the result, it is cached.
|
||||
const GSList *get_icon_locations();
|
||||
|
||||
extern gboolean debug_icons;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -64,6 +64,8 @@ void launcher_reload_hidden_icons(Launcher *launcher);
|
||||
void launcher_icon_on_change_layout(void *obj);
|
||||
int launcher_compute_desired_size(void *obj);
|
||||
|
||||
void relayout_launcher();
|
||||
|
||||
void default_launcher()
|
||||
{
|
||||
launcher_enabled = 0;
|
||||
@@ -95,6 +97,7 @@ void init_launcher_panel(void *p)
|
||||
launcher->area._draw_foreground = NULL;
|
||||
launcher->area.size_mode = LAYOUT_FIXED;
|
||||
launcher->area._resize = resize_launcher;
|
||||
launcher->area._on_change_layout = relayout_launcher;
|
||||
launcher->area._compute_desired_size = launcher_compute_desired_size;
|
||||
launcher->area.resize_needed = 1;
|
||||
schedule_redraw(&launcher->area);
|
||||
@@ -294,7 +297,7 @@ gboolean resize_launcher(void *obj)
|
||||
launcherIcon->y = posy;
|
||||
launcherIcon->x = posx;
|
||||
launcher_icon_on_change_layout(launcherIcon);
|
||||
// printf("launcher %d : %d,%d\n", i, posx, posy);
|
||||
// fprintf(stderr, "tint2: launcher %d : %d,%d\n", i, posx, posy);
|
||||
if (panel_horizontal) {
|
||||
if (i % icons_per_column) {
|
||||
posy += launcher->icon_size + launcher->area.paddingx;
|
||||
@@ -325,6 +328,17 @@ gboolean resize_launcher(void *obj)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void relayout_launcher(void *obj)
|
||||
{
|
||||
Launcher *launcher = (Launcher *)obj;
|
||||
for (GSList *l = launcher->list_icons; l; l = l->next) {
|
||||
LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
|
||||
if (!launcherIcon->area.on_screen)
|
||||
continue;
|
||||
launcher_icon_on_change_layout(launcherIcon);
|
||||
}
|
||||
}
|
||||
|
||||
// Here we override the default layout of the icons; normally Area layouts its children
|
||||
// in a stack; we need to layout them in a kind of table
|
||||
void launcher_icon_on_change_layout(void *obj)
|
||||
@@ -371,7 +385,12 @@ void draw_launcher_icon(void *obj, cairo_t *c)
|
||||
void launcher_icon_dump_geometry(void *obj, int indent)
|
||||
{
|
||||
LauncherIcon *launcherIcon = (LauncherIcon *)obj;
|
||||
fprintf(stderr, "%*sIcon: w = h = %d, name = %s\n", indent, "", launcherIcon->icon_size, launcherIcon->icon_name);
|
||||
fprintf(stderr,
|
||||
"tint2: %*sIcon: w = h = %d, name = %s\n",
|
||||
indent,
|
||||
"",
|
||||
launcherIcon->icon_size,
|
||||
launcherIcon->icon_name);
|
||||
}
|
||||
|
||||
Imlib_Image scale_icon(Imlib_Image original, int icon_size)
|
||||
@@ -415,13 +434,26 @@ void free_icon(Imlib_Image icon)
|
||||
}
|
||||
}
|
||||
|
||||
void launcher_action(LauncherIcon *icon, XEvent *evt)
|
||||
void launcher_action(LauncherIcon *icon, XEvent *evt, int x, int y)
|
||||
{
|
||||
launcher_reload_icon((Launcher *)icon->area.parent, icon);
|
||||
launcher_reload_hidden_icons((Launcher *)icon->area.parent);
|
||||
|
||||
if (evt->type == ButtonPress || evt->type == ButtonRelease)
|
||||
tint_exec(icon->cmd, icon->cwd, icon->icon_tooltip, evt->xbutton.time);
|
||||
if (evt->type == ButtonPress || evt->type == ButtonRelease) {
|
||||
GString *cmd = g_string_new(icon->cmd);
|
||||
tint2_g_string_replace(cmd, "%f", "");
|
||||
tint2_g_string_replace(cmd, "%F", "");
|
||||
tint_exec(cmd->str,
|
||||
icon->cwd,
|
||||
icon->icon_tooltip,
|
||||
evt->xbutton.time,
|
||||
&icon->area,
|
||||
x,
|
||||
y,
|
||||
icon->start_in_terminal,
|
||||
icon->startup_notification);
|
||||
g_string_free(cmd, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Populates the list_icons list from the list_apps list
|
||||
@@ -476,6 +508,8 @@ void launcher_reload_icon(Launcher *launcher, LauncherIcon *launcherIcon)
|
||||
launcherIcon->cwd = strdup(entry.cwd);
|
||||
else
|
||||
launcherIcon->cwd = NULL;
|
||||
launcherIcon->start_in_terminal = entry.start_in_terminal;
|
||||
launcherIcon->startup_notification = entry.startup_notification;
|
||||
if (launcherIcon->icon_name)
|
||||
free(launcherIcon->icon_name);
|
||||
launcherIcon->icon_name = entry.icon ? strdup(entry.icon) : strdup(DEFAULT_ICON);
|
||||
@@ -531,7 +565,7 @@ void launcher_reload_icon_image(Launcher *launcher, LauncherIcon *launcherIcon)
|
||||
free_icon(original);
|
||||
free(launcherIcon->icon_path);
|
||||
launcherIcon->icon_path = new_icon_path;
|
||||
// fprintf(stderr, "launcher.c %d: Using icon %s\n", __LINE__, launcherIcon->icon_path);
|
||||
// fprintf(stderr, "tint2: launcher.c %d: Using icon %s\n", __LINE__, launcherIcon->icon_path);
|
||||
|
||||
if (panel_config.mouse_effects) {
|
||||
launcherIcon->image_hover = adjust_icon(launcherIcon->image,
|
||||
|
||||
@@ -33,6 +33,8 @@ typedef struct LauncherIcon {
|
||||
Imlib_Image image_pressed;
|
||||
char *cmd;
|
||||
char *cwd;
|
||||
gboolean start_in_terminal;
|
||||
gboolean startup_notification;
|
||||
char *icon_name;
|
||||
char *icon_path;
|
||||
char *icon_tooltip;
|
||||
@@ -67,7 +69,7 @@ void launcher_default_icon_theme_changed();
|
||||
|
||||
// Populates the list_icons list
|
||||
void launcher_load_icons(Launcher *launcher);
|
||||
void launcher_action(LauncherIcon *icon, XEvent *e);
|
||||
void launcher_action(LauncherIcon *icon, XEvent *e, int x, int y);
|
||||
|
||||
void test_launcher_read_desktop_file();
|
||||
void test_launcher_read_theme_file();
|
||||
|
||||
@@ -48,7 +48,7 @@ void xsettings_notify_cb(const char *name, XSettingsAction action, XSettingsSett
|
||||
{
|
||||
if ((action == XSETTINGS_ACTION_NEW || action == XSETTINGS_ACTION_CHANGED) && name != NULL && setting != NULL) {
|
||||
if (strcmp(name, "Net/IconThemeName") == 0 && setting->type == XSETTINGS_TYPE_STRING) {
|
||||
fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string);
|
||||
fprintf(stderr, "tint2: xsettings: %s = %s\n", name, setting->data.v_string);
|
||||
if (icon_theme_name_xsettings) {
|
||||
if (strcmp(icon_theme_name_xsettings, setting->data.v_string) == 0)
|
||||
return;
|
||||
@@ -57,7 +57,7 @@ void xsettings_notify_cb(const char *name, XSettingsAction action, XSettingsSett
|
||||
icon_theme_name_xsettings = strdup(setting->data.v_string);
|
||||
default_icon_theme_changed();
|
||||
} else if (strcmp(name, "Gtk/FontName") == 0 && setting->type == XSETTINGS_TYPE_STRING) {
|
||||
fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string);
|
||||
fprintf(stderr, "tint2: xsettings: %s = %s\n", name, setting->data.v_string);
|
||||
if (default_font) {
|
||||
if (strcmp(default_font, setting->data.v_string) == 0)
|
||||
return;
|
||||
@@ -191,7 +191,7 @@ static XSettingsList *parse_settings(unsigned char *data, size_t len)
|
||||
|
||||
result = fetch_card8(&buffer, (CARD8 *)&buffer.byte_order);
|
||||
if (buffer.byte_order != MSBFirst && buffer.byte_order != LSBFirst) {
|
||||
fprintf(stderr, "Invalid byte order %x in XSETTINGS property\n", buffer.byte_order);
|
||||
fprintf(stderr, "tint2: Invalid byte order %x in XSETTINGS property\n", buffer.byte_order);
|
||||
result = XSETTINGS_FAILED;
|
||||
goto out;
|
||||
}
|
||||
@@ -312,13 +312,13 @@ out:
|
||||
if (result != XSETTINGS_SUCCESS) {
|
||||
switch (result) {
|
||||
case XSETTINGS_NO_MEM:
|
||||
fprintf(stderr, "Out of memory reading XSETTINGS property\n");
|
||||
fprintf(stderr, "tint2: Out of memory reading XSETTINGS property\n");
|
||||
break;
|
||||
case XSETTINGS_ACCESS:
|
||||
fprintf(stderr, "Invalid XSETTINGS property (read off end)\n");
|
||||
fprintf(stderr, "tint2: Invalid XSETTINGS property (read off end)\n");
|
||||
break;
|
||||
case XSETTINGS_DUPLICATE_ENTRY:
|
||||
fprintf(stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name);
|
||||
fprintf(stderr, "tint2: Duplicate XSETTINGS entry for '%s'\n", setting->name);
|
||||
case XSETTINGS_FAILED:
|
||||
case XSETTINGS_SUCCESS:
|
||||
case XSETTINGS_NO_ENTRY:
|
||||
@@ -365,7 +365,7 @@ static void read_settings(XSettingsClient *client)
|
||||
|
||||
if (result == Success && type == server.atom._XSETTINGS_SETTINGS) {
|
||||
if (format != 8) {
|
||||
fprintf(stderr, "Invalid format for XSETTINGS property %d", format);
|
||||
fprintf(stderr, "tint2: Invalid format for XSETTINGS property %d", format);
|
||||
} else
|
||||
client->settings = parse_settings(data, n_items);
|
||||
XFree(data);
|
||||
@@ -420,7 +420,7 @@ XSettingsClient *xsettings_client_new(Display *display,
|
||||
check_manager_window(client);
|
||||
|
||||
if (client->manager_window == None) {
|
||||
printf("No XSETTINGS manager, tint2 uses config option 'launcher_icon_theme'.\n");
|
||||
fprintf(stderr, "tint2: No XSETTINGS manager, tint2 uses config option 'launcher_icon_theme'.\n");
|
||||
free(client);
|
||||
return NULL;
|
||||
} else {
|
||||
|
||||
806
src/main.c
Normal file
806
src/main.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Tint2 panel
|
||||
*
|
||||
* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
|
||||
* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr) from Omega distribution
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlocale.h>
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <Imlib2.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef HAVE_SN
|
||||
#include <libsn/sn.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "drag_and_drop.h"
|
||||
#include "fps_distribution.h"
|
||||
#include "init.h"
|
||||
#include "launcher.h"
|
||||
#include "mouse_actions.h"
|
||||
#include "panel.h"
|
||||
#include "server.h"
|
||||
#include "signals.h"
|
||||
#include "systraybar.h"
|
||||
#include "task.h"
|
||||
#include "taskbar.h"
|
||||
#include "tooltip.h"
|
||||
#include "timer.h"
|
||||
#include "tracing.h"
|
||||
#include "uevent.h"
|
||||
#include "version.h"
|
||||
#include "window.h"
|
||||
#include "xsettings-client.h"
|
||||
|
||||
// Global process state variables
|
||||
|
||||
XSettingsClient *xsettings_client = NULL;
|
||||
|
||||
gboolean debug_fps = FALSE;
|
||||
gboolean debug_frames = FALSE;
|
||||
static int frame = 0;
|
||||
double tracing_fps_threshold = 60;
|
||||
static double ts_event_read;
|
||||
static double ts_event_processed;
|
||||
static double ts_render_finished;
|
||||
static double ts_flush_finished;
|
||||
|
||||
static gboolean first_render;
|
||||
|
||||
void handle_event_property_notify(XEvent *e)
|
||||
{
|
||||
gboolean debug = FALSE;
|
||||
|
||||
Window win = e->xproperty.window;
|
||||
Atom at = e->xproperty.atom;
|
||||
|
||||
if (xsettings_client)
|
||||
xsettings_client_process_event(xsettings_client, e);
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
Panel *p = &panels[i];
|
||||
if (win == p->main_win) {
|
||||
if (at == server.atom._NET_WM_DESKTOP && get_window_desktop(p->main_win) != ALL_DESKTOPS)
|
||||
replace_panel_all_desktops(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (win == server.root_win) {
|
||||
if (!server.got_root_win) {
|
||||
XSelectInput(server.display, server.root_win, PropertyChangeMask | StructureNotifyMask);
|
||||
server.got_root_win = TRUE;
|
||||
}
|
||||
|
||||
// Change name of desktops
|
||||
else if (at == server.atom._NET_DESKTOP_NAMES) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d: win = root, atom = _NET_DESKTOP_NAMES\n", __FUNCTION__, __LINE__);
|
||||
update_desktop_names();
|
||||
}
|
||||
// Change desktops
|
||||
else if (at == server.atom._NET_NUMBER_OF_DESKTOPS || at == server.atom._NET_DESKTOP_GEOMETRY ||
|
||||
at == server.atom._NET_DESKTOP_VIEWPORT || at == server.atom._NET_WORKAREA ||
|
||||
at == server.atom._NET_CURRENT_DESKTOP) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d: win = root, atom = ?? desktops changed\n", __FUNCTION__, __LINE__);
|
||||
if (!taskbar_enabled)
|
||||
return;
|
||||
int old_num_desktops = server.num_desktops;
|
||||
int old_desktop = server.desktop;
|
||||
server_get_number_of_desktops();
|
||||
server.desktop = get_current_desktop();
|
||||
if (old_num_desktops != server.num_desktops) { // If number of desktop changed
|
||||
if (server.num_desktops <= server.desktop) {
|
||||
server.desktop = server.num_desktops - 1;
|
||||
}
|
||||
cleanup_taskbar();
|
||||
init_taskbar();
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
init_taskbar_panel(&panels[i]);
|
||||
set_panel_items_order(&panels[i]);
|
||||
panels[i].area.resize_needed = 1;
|
||||
}
|
||||
taskbar_refresh_tasklist();
|
||||
reset_active_task();
|
||||
update_all_taskbars_visibility();
|
||||
if (old_desktop != server.desktop)
|
||||
tooltip_trigger_hide();
|
||||
schedule_panel_redraw();
|
||||
} else if (old_desktop != server.desktop) {
|
||||
tooltip_trigger_hide();
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
Panel *panel = &panels[i];
|
||||
set_taskbar_state(&panel->taskbar[old_desktop], TASKBAR_NORMAL);
|
||||
set_taskbar_state(&panel->taskbar[server.desktop], TASKBAR_ACTIVE);
|
||||
// check ALL_DESKTOPS task => resize taskbar
|
||||
Taskbar *taskbar;
|
||||
if (server.num_desktops > old_desktop) {
|
||||
taskbar = &panel->taskbar[old_desktop];
|
||||
GList *l = taskbar->area.children;
|
||||
if (taskbarname_enabled)
|
||||
l = l->next;
|
||||
for (; l; l = l->next) {
|
||||
Task *task = l->data;
|
||||
if (task->desktop == ALL_DESKTOPS) {
|
||||
task->area.on_screen = always_show_all_desktop_tasks;
|
||||
taskbar->area.resize_needed = 1;
|
||||
schedule_panel_redraw();
|
||||
if (taskbar_mode == MULTI_DESKTOP)
|
||||
panel->area.resize_needed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
taskbar = &panel->taskbar[server.desktop];
|
||||
GList *l = taskbar->area.children;
|
||||
if (taskbarname_enabled)
|
||||
l = l->next;
|
||||
for (; l; l = l->next) {
|
||||
Task *task = l->data;
|
||||
if (task->desktop == ALL_DESKTOPS) {
|
||||
task->area.on_screen = TRUE;
|
||||
taskbar->area.resize_needed = 1;
|
||||
if (taskbar_mode == MULTI_DESKTOP)
|
||||
panel->area.resize_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (server.viewports) {
|
||||
GList *need_update = NULL;
|
||||
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init(&iter, win_to_task);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
Window task_win = *(Window *)key;
|
||||
Task *task = get_task(task_win);
|
||||
if (task) {
|
||||
int desktop = get_window_desktop(task_win);
|
||||
if (desktop != task->desktop) {
|
||||
need_update = g_list_append(need_update, task);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (l = need_update; l; l = l->next) {
|
||||
Task *task = l->data;
|
||||
task_update_desktop(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Window list
|
||||
else if (at == server.atom._NET_CLIENT_LIST) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d: win = root, atom = _NET_CLIENT_LIST\n", __FUNCTION__, __LINE__);
|
||||
taskbar_refresh_tasklist();
|
||||
update_all_taskbars_visibility();
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
// Change active
|
||||
else if (at == server.atom._NET_ACTIVE_WINDOW) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d: win = root, atom = _NET_ACTIVE_WINDOW\n", __FUNCTION__, __LINE__);
|
||||
reset_active_task();
|
||||
schedule_panel_redraw();
|
||||
} else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d: win = root, atom = _XROOTPMAP_ID\n", __FUNCTION__, __LINE__);
|
||||
// change Wallpaper
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
set_panel_background(&panels[i]);
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
} else {
|
||||
TrayWindow *traywin = systray_find_icon(win);
|
||||
if (traywin) {
|
||||
systray_property_notify(traywin, e);
|
||||
return;
|
||||
}
|
||||
|
||||
Task *task = get_task(win);
|
||||
if (debug) {
|
||||
char *atom_name = XGetAtomName(server.display, at);
|
||||
fprintf(stderr,
|
||||
"%s %d: win = %ld, task = %s, atom = %s\n",
|
||||
__FUNCTION__,
|
||||
__LINE__,
|
||||
win,
|
||||
task ? (task->title ? task->title : "??") : "null",
|
||||
atom_name);
|
||||
XFree(atom_name);
|
||||
}
|
||||
if (!task) {
|
||||
if (debug)
|
||||
fprintf(stderr, "tint2: %s %d\n", __FUNCTION__, __LINE__);
|
||||
if (at == server.atom._NET_WM_STATE) {
|
||||
// xfce4 sends _NET_WM_STATE after minimized to tray, so we need to check if window is mapped
|
||||
// if it is mapped and not set as skip_taskbar, we must add it to our task list
|
||||
XWindowAttributes wa;
|
||||
XGetWindowAttributes(server.display, win, &wa);
|
||||
if (wa.map_state == IsViewable && !window_is_skip_taskbar(win)) {
|
||||
if ((task = add_task(win)))
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// fprintf(stderr, "tint2: atom root_win = %s, %s\n", XGetAtomName(server.display, at), task->title);
|
||||
|
||||
// Window title changed
|
||||
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();
|
||||
}
|
||||
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
||||
sort_taskbar_for_win(win);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
// Demand attention
|
||||
else if (at == server.atom._NET_WM_STATE) {
|
||||
if (debug) {
|
||||
int count;
|
||||
Atom *atom_state = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int j = 0; j < count; j++) {
|
||||
char *atom_state_name = XGetAtomName(server.display, atom_state[j]);
|
||||
fprintf(stderr, "tint2: %s %d: _NET_WM_STATE = %s\n", __FUNCTION__, __LINE__, atom_state_name);
|
||||
XFree(atom_state_name);
|
||||
}
|
||||
XFree(atom_state);
|
||||
}
|
||||
if (window_is_urgent(win)) {
|
||||
add_urgent(task);
|
||||
}
|
||||
if (window_is_skip_taskbar(win)) {
|
||||
remove_task(task);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
} else if (at == server.atom.WM_STATE) {
|
||||
// Iconic state
|
||||
TaskState state = (active_task && task->win == active_task->win ? TASK_ACTIVE : TASK_NORMAL);
|
||||
if (window_is_iconified(win))
|
||||
state = TASK_ICONIFIED;
|
||||
set_task_state(task, state);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
// Window icon changed
|
||||
else if (at == server.atom._NET_WM_ICON) {
|
||||
task_update_icon(task);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
// Window desktop changed
|
||||
else if (at == server.atom._NET_WM_DESKTOP) {
|
||||
int desktop = get_window_desktop(win);
|
||||
// fprintf(stderr, "tint2: Window desktop changed %d, %d\n", task->desktop, desktop);
|
||||
// bug in windowmaker : send unecessary 'desktop changed' when focus changed
|
||||
if (desktop != task->desktop) {
|
||||
task_update_desktop(task);
|
||||
}
|
||||
} else if (at == server.atom.WM_HINTS) {
|
||||
XWMHints *wmhints = XGetWMHints(server.display, win);
|
||||
if (wmhints && wmhints->flags & XUrgencyHint) {
|
||||
add_urgent(task);
|
||||
}
|
||||
XFree(wmhints);
|
||||
task_update_icon(task);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
if (!server.got_root_win)
|
||||
server.root_win = RootWindow(server.display, server.screen);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_event_expose(XEvent *e)
|
||||
{
|
||||
Panel *panel;
|
||||
panel = get_panel(e->xany.window);
|
||||
if (!panel)
|
||||
return;
|
||||
// TODO : one panel_refresh per panel ?
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
void handle_event_configure_notify(XEvent *e)
|
||||
{
|
||||
Window win = e->xconfigure.window;
|
||||
|
||||
// change in root window (xrandr)
|
||||
if (win == server.root_win) {
|
||||
emit_self_restart("configuration change in the root window");
|
||||
return;
|
||||
}
|
||||
|
||||
TrayWindow *traywin = systray_find_icon(win);
|
||||
if (traywin) {
|
||||
systray_reconfigure_event(traywin, e);
|
||||
return;
|
||||
}
|
||||
|
||||
// 'win' move in another monitor
|
||||
if (num_panels > 1 || hide_task_diff_monitor) {
|
||||
Task *task = get_task(win);
|
||||
if (task) {
|
||||
Panel *p = task->area.panel;
|
||||
int monitor = get_window_monitor(win);
|
||||
if ((hide_task_diff_monitor && p->monitor != monitor && task->area.on_screen) ||
|
||||
(hide_task_diff_monitor && p->monitor == monitor && !task->area.on_screen) ||
|
||||
(p->monitor != monitor && num_panels > 1)) {
|
||||
remove_task(task);
|
||||
task = add_task(win);
|
||||
if (win == get_active_window()) {
|
||||
set_task_state(task, TASK_ACTIVE);
|
||||
active_task = task;
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (server.viewports) {
|
||||
Task *task = get_task(win);
|
||||
if (task) {
|
||||
int desktop = get_window_desktop(win);
|
||||
if (task->desktop != desktop) {
|
||||
task_update_desktop(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort_taskbar_for_win(win);
|
||||
}
|
||||
|
||||
gboolean handle_x_event_autohide(XEvent *e)
|
||||
{
|
||||
Panel *panel = get_panel(e->xany.window);
|
||||
if (panel && panel_autohide) {
|
||||
if (e->type == EnterNotify)
|
||||
autohide_trigger_show(panel);
|
||||
else if (e->type == LeaveNotify)
|
||||
autohide_trigger_hide(panel);
|
||||
if (panel->is_hidden) {
|
||||
if (e->type == ClientMessage && e->xclient.message_type == server.atom.XdndPosition) {
|
||||
hidden_panel_shown_for_dnd = TRUE;
|
||||
autohide_show(panel);
|
||||
} else {
|
||||
// discard further processing of this event because the panel is not visible yet
|
||||
return TRUE;
|
||||
}
|
||||
} else if (hidden_panel_shown_for_dnd && e->type == ClientMessage &&
|
||||
e->xclient.message_type == server.atom.XdndLeave) {
|
||||
hidden_panel_shown_for_dnd = FALSE;
|
||||
autohide_hide(panel);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void handle_x_event(XEvent *e)
|
||||
{
|
||||
#if HAVE_SN
|
||||
if (startup_notifications)
|
||||
sn_display_process_event(server.sn_display, e);
|
||||
#endif // HAVE_SN
|
||||
|
||||
if (handle_x_event_autohide(e))
|
||||
return;
|
||||
|
||||
Panel *panel = get_panel(e->xany.window);
|
||||
switch (e->type) {
|
||||
case ButtonPress: {
|
||||
tooltip_hide(0);
|
||||
handle_mouse_press_event(e);
|
||||
Area *area = find_area_under_mouse(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (panel_config.mouse_effects)
|
||||
mouse_over(area, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
case ButtonRelease: {
|
||||
handle_mouse_release_event(e);
|
||||
Area *area = find_area_under_mouse(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (panel_config.mouse_effects)
|
||||
mouse_over(area, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionNotify: {
|
||||
unsigned int button_mask = Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
|
||||
if (e->xmotion.state & button_mask)
|
||||
handle_mouse_move_event(e);
|
||||
|
||||
Area *area = find_area_under_mouse(panel, e->xmotion.x, e->xmotion.y);
|
||||
if (area->_get_tooltip_text)
|
||||
tooltip_trigger_show(area, panel, e);
|
||||
else
|
||||
tooltip_trigger_hide();
|
||||
if (panel_config.mouse_effects)
|
||||
mouse_over(area, e->xmotion.state & button_mask);
|
||||
break;
|
||||
}
|
||||
|
||||
case LeaveNotify: {
|
||||
tooltip_trigger_hide();
|
||||
if (panel_config.mouse_effects)
|
||||
mouse_out();
|
||||
break;
|
||||
}
|
||||
|
||||
case Expose:
|
||||
handle_event_expose(e);
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
handle_event_property_notify(e);
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
handle_event_configure_notify(e);
|
||||
break;
|
||||
|
||||
case ConfigureRequest: {
|
||||
TrayWindow *traywin = systray_find_icon(e->xany.window);
|
||||
if (traywin)
|
||||
systray_reconfigure_event(traywin, e);
|
||||
break;
|
||||
}
|
||||
|
||||
case ResizeRequest: {
|
||||
TrayWindow *traywin = systray_find_icon(e->xany.window);
|
||||
if (traywin)
|
||||
systray_resize_request_event(traywin, e);
|
||||
break;
|
||||
}
|
||||
|
||||
case ReparentNotify: {
|
||||
if (!systray_enabled)
|
||||
break;
|
||||
Panel *systray_panel = (Panel *)systray.area.panel;
|
||||
if (e->xany.window == systray_panel->main_win) // don't care
|
||||
break;
|
||||
TrayWindow *traywin = systray_find_icon(e->xreparent.window);
|
||||
if (traywin) {
|
||||
if (traywin->win == e->xreparent.window) {
|
||||
if (traywin->parent == e->xreparent.parent) {
|
||||
embed_icon(traywin);
|
||||
} else {
|
||||
remove_icon(traywin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UnmapNotify:
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
if (e->xany.window == server.composite_manager) {
|
||||
// Stop real_transparency
|
||||
emit_self_restart("compositor shutdown");
|
||||
break;
|
||||
}
|
||||
if (e->xany.window == g_tooltip.window || !systray_enabled)
|
||||
break;
|
||||
for (GSList *it = systray.list_icons; it; it = g_slist_next(it)) {
|
||||
if (((TrayWindow *)it->data)->win == e->xany.window) {
|
||||
systray_destroy_event((TrayWindow *)it->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ClientMessage: {
|
||||
XClientMessageEvent *ev = &e->xclient;
|
||||
if (ev->data.l[1] == server.atom._NET_WM_CM_S0) {
|
||||
if (ev->data.l[2] == None) {
|
||||
// Stop real_transparency
|
||||
emit_self_restart("compositor changed");
|
||||
} else {
|
||||
// Start real_transparency
|
||||
emit_self_restart("compositor changed");
|
||||
}
|
||||
}
|
||||
if (systray_enabled && e->xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE &&
|
||||
e->xclient.format == 32 && e->xclient.window == net_sel_win) {
|
||||
handle_systray_event(&e->xclient);
|
||||
} else if (e->xclient.message_type == server.atom.XdndEnter) {
|
||||
handle_dnd_enter(&e->xclient);
|
||||
} else if (e->xclient.message_type == server.atom.XdndPosition) {
|
||||
handle_dnd_position(&e->xclient);
|
||||
} else if (e->xclient.message_type == server.atom.XdndDrop) {
|
||||
handle_dnd_drop(&e->xclient);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SelectionNotify: {
|
||||
handle_dnd_selection_notify(&e->xselection);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (e->type == server.xdamage_event_type) {
|
||||
XDamageNotifyEvent *de = (XDamageNotifyEvent *)e;
|
||||
TrayWindow *traywin = systray_find_icon(de->drawable);
|
||||
if (traywin)
|
||||
systray_render_icon(traywin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_x_events()
|
||||
{
|
||||
if (XPending(server.display) > 0) {
|
||||
XEvent e;
|
||||
XNextEvent(server.display, &e);
|
||||
if (debug_fps)
|
||||
ts_event_read = get_time();
|
||||
|
||||
handle_x_event(&e);
|
||||
}
|
||||
}
|
||||
|
||||
void prepare_fd_set(fd_set *set, int *max_fd)
|
||||
{
|
||||
FD_ZERO(set);
|
||||
FD_SET(server.x11_fd, set);
|
||||
*max_fd = server.x11_fd;
|
||||
if (sigchild_pipe_valid) {
|
||||
FD_SET(sigchild_pipe[0], set);
|
||||
*max_fd = MAX(*max_fd, sigchild_pipe[0]);
|
||||
}
|
||||
for (GList *l = panel_config.execp_list; l; l = l->next) {
|
||||
Execp *execp = (Execp *)l->data;
|
||||
int fd = execp->backend->child_pipe_stdout;
|
||||
if (fd > 0) {
|
||||
FD_SET(fd, set);
|
||||
*max_fd = MAX(*max_fd, fd);
|
||||
}
|
||||
fd = execp->backend->child_pipe_stderr;
|
||||
if (fd > 0) {
|
||||
FD_SET(fd, set);
|
||||
*max_fd = MAX(*max_fd, fd);
|
||||
}
|
||||
}
|
||||
if (uevent_fd > 0) {
|
||||
FD_SET(uevent_fd, set);
|
||||
*max_fd = MAX(*max_fd, uevent_fd);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_panel_refresh()
|
||||
{
|
||||
if (debug_fps)
|
||||
ts_event_processed = get_time();
|
||||
panel_refresh = FALSE;
|
||||
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
Panel *panel = &panels[i];
|
||||
if (!first_render)
|
||||
shrink_panel(panel);
|
||||
|
||||
if (!panel->is_hidden || panel->area.resize_needed) {
|
||||
if (panel->temp_pmap)
|
||||
XFreePixmap(server.display, panel->temp_pmap);
|
||||
panel->temp_pmap = XCreatePixmap(server.display,
|
||||
server.root_win,
|
||||
panel->area.width,
|
||||
panel->area.height,
|
||||
server.depth);
|
||||
render_panel(panel);
|
||||
}
|
||||
|
||||
if (panel->is_hidden) {
|
||||
if (!panel->hidden_pixmap) {
|
||||
panel->hidden_pixmap = XCreatePixmap(server.display,
|
||||
server.root_win,
|
||||
panel->hidden_width,
|
||||
panel->hidden_height,
|
||||
server.depth);
|
||||
int xoff = 0, yoff = 0;
|
||||
if (panel_horizontal && panel_position & BOTTOM)
|
||||
yoff = panel->area.height - panel->hidden_height;
|
||||
else if (!panel_horizontal && panel_position & RIGHT)
|
||||
xoff = panel->area.width - panel->hidden_width;
|
||||
XCopyArea(server.display,
|
||||
panel->area.pix,
|
||||
panel->hidden_pixmap,
|
||||
server.gc,
|
||||
xoff,
|
||||
yoff,
|
||||
panel->hidden_width,
|
||||
panel->hidden_height,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
XCopyArea(server.display,
|
||||
panel->hidden_pixmap,
|
||||
panel->main_win,
|
||||
server.gc,
|
||||
0,
|
||||
0,
|
||||
panel->hidden_width,
|
||||
panel->hidden_height,
|
||||
0,
|
||||
0);
|
||||
XSetWindowBackgroundPixmap(server.display, panel->main_win, panel->hidden_pixmap);
|
||||
} else {
|
||||
XCopyArea(server.display,
|
||||
panel->temp_pmap,
|
||||
panel->main_win,
|
||||
server.gc,
|
||||
0,
|
||||
0,
|
||||
panel->area.width,
|
||||
panel->area.height,
|
||||
0,
|
||||
0);
|
||||
if (panel == (Panel *)systray.area.panel) {
|
||||
if (refresh_systray && panel && !panel->is_hidden) {
|
||||
refresh_systray = FALSE;
|
||||
XSetWindowBackgroundPixmap(server.display, panel->main_win, panel->temp_pmap);
|
||||
refresh_systray_icons();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (first_render) {
|
||||
first_render = FALSE;
|
||||
if (panel_shrink)
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
if (debug_fps)
|
||||
ts_render_finished = get_time();
|
||||
XFlush(server.display);
|
||||
|
||||
if (debug_fps && ts_event_read > 0) {
|
||||
ts_flush_finished = get_time();
|
||||
double period = ts_flush_finished - ts_event_read;
|
||||
double fps = 1.0 / period;
|
||||
sample_fps(fps);
|
||||
double proc_ratio = (ts_event_processed - ts_event_read) / period;
|
||||
double render_ratio = (ts_render_finished - ts_event_processed) / period;
|
||||
double flush_ratio = (ts_flush_finished - ts_render_finished) / period;
|
||||
double fps_low, fps_median, fps_high, fps_samples;
|
||||
fps_compute_stats(&fps_low, &fps_median, &fps_high, &fps_samples);
|
||||
fprintf(stderr,
|
||||
BLUE "frame %d: fps = %.0f (low %.0f, med %.0f, high %.0f, samples %.0f) : processing %.0f%%, "
|
||||
"rendering %.0f%%, "
|
||||
"flushing %.0f%%" RESET "\n",
|
||||
frame,
|
||||
fps,
|
||||
fps_low,
|
||||
fps_median,
|
||||
fps_high,
|
||||
fps_samples,
|
||||
proc_ratio * 100,
|
||||
render_ratio * 100,
|
||||
flush_ratio * 100);
|
||||
#ifdef HAVE_TRACING
|
||||
stop_tracing();
|
||||
if (fps <= tracing_fps_threshold) {
|
||||
print_tracing_events();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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);
|
||||
save_panel_screenshot(&panels[i], path);
|
||||
}
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
|
||||
void run_tint2_event_loop()
|
||||
{
|
||||
ts_event_read = 0;
|
||||
ts_event_processed = 0;
|
||||
ts_render_finished = 0;
|
||||
ts_flush_finished = 0;
|
||||
first_render = TRUE;
|
||||
|
||||
while (!get_signal_pending()) {
|
||||
if (panel_refresh)
|
||||
handle_panel_refresh();
|
||||
|
||||
fd_set fds;
|
||||
int max_fd;
|
||||
prepare_fd_set(&fds, &max_fd);
|
||||
|
||||
// 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) {
|
||||
#ifdef HAVE_TRACING
|
||||
start_tracing((void*)run_tint2_event_loop);
|
||||
#endif
|
||||
uevent_handler();
|
||||
handle_sigchld_events();
|
||||
handle_execp_events();
|
||||
handle_x_events();
|
||||
}
|
||||
|
||||
handle_expired_timers();
|
||||
}
|
||||
}
|
||||
|
||||
void tint2(int argc, char **argv, gboolean *restart)
|
||||
{
|
||||
init(argc, argv);
|
||||
|
||||
if (snapshot_path) {
|
||||
save_screenshot(snapshot_path);
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
dnd_init();
|
||||
uevent_init();
|
||||
run_tint2_event_loop();
|
||||
|
||||
if (get_signal_pending()) {
|
||||
cleanup();
|
||||
if (get_signal_pending() == SIGUSR1) {
|
||||
fprintf(stderr, YELLOW "tint2: %s %d: restarting tint2..." RESET "\n", __FILE__, __LINE__);
|
||||
*restart = TRUE;
|
||||
return;
|
||||
} else if (get_signal_pending() == SIGUSR2) {
|
||||
fprintf(stderr, YELLOW "tint2: %s %d: reexecuting tint2..." RESET "\n", __FILE__, __LINE__);
|
||||
if (execvp(argv[0], argv) == -1) {
|
||||
fprintf(stderr, RED "tint2: %s %d: failed!" RESET "\n", __FILE__, __LINE__);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// SIGINT, SIGTERM, SIGHUP etc.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
gboolean restart;
|
||||
do {
|
||||
restart = FALSE;
|
||||
tint2(argc, argv, &restart);
|
||||
} while(restart);
|
||||
return 0;
|
||||
}
|
||||
287
src/mouse_actions.c
Normal file
287
src/mouse_actions.c
Normal file
@@ -0,0 +1,287 @@
|
||||
/**************************************************************************
|
||||
* Copyright (C) 2017 tint2 authors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "drag_and_drop.h"
|
||||
#include "panel.h"
|
||||
#include "server.h"
|
||||
#include "task.h"
|
||||
#include "window.h"
|
||||
|
||||
gboolean tint2_handles_click(Panel *panel, XButtonEvent *e)
|
||||
{
|
||||
Task *task = click_task(panel, e->x, e->y);
|
||||
if (task) {
|
||||
if ((e->button == 1 && mouse_left != 0) || (e->button == 2 && mouse_middle != 0) ||
|
||||
(e->button == 3 && mouse_right != 0) || (e->button == 4 && mouse_scroll_up != 0) ||
|
||||
(e->button == 5 && mouse_scroll_down != 0)) {
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
LauncherIcon *icon = click_launcher_icon(panel, e->x, e->y);
|
||||
if (icon) {
|
||||
if (e->button == 1) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// no launcher/task clicked --> check if taskbar clicked
|
||||
Taskbar *taskbar = click_taskbar(panel, e->x, e->y);
|
||||
if (taskbar && e->button == 1 && taskbar_mode == MULTI_DESKTOP)
|
||||
return TRUE;
|
||||
if (click_clock(panel, e->x, e->y)) {
|
||||
if ((e->button == 1 && clock_lclick_command) || (e->button == 2 && clock_mclick_command) ||
|
||||
(e->button == 3 && clock_rclick_command) || (e->button == 4 && clock_uwheel_command) ||
|
||||
(e->button == 5 && clock_dwheel_command))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef ENABLE_BATTERY
|
||||
if (click_battery(panel, e->x, e->y)) {
|
||||
if ((e->button == 1 && battery_lclick_command) || (e->button == 2 && battery_mclick_command) ||
|
||||
(e->button == 3 && battery_rclick_command) || (e->button == 4 && battery_uwheel_command) ||
|
||||
(e->button == 5 && battery_dwheel_command))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
if (click_execp(panel, e->x, e->y))
|
||||
return TRUE;
|
||||
if (click_button(panel, e->x, e->y))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void handle_mouse_press_event(XEvent *e)
|
||||
{
|
||||
Panel *panel = get_panel(e->xany.window);
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
if (wm_menu && !tint2_handles_click(panel, &e->xbutton)) {
|
||||
forward_click(e);
|
||||
return;
|
||||
}
|
||||
task_drag = click_task(panel, e->xbutton.x, e->xbutton.y);
|
||||
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
}
|
||||
|
||||
void handle_mouse_move_event(XEvent *e)
|
||||
{
|
||||
Panel *panel = get_panel(e->xany.window);
|
||||
if (!panel || !task_drag)
|
||||
return;
|
||||
|
||||
// Find the taskbar on the event's location
|
||||
Taskbar *event_taskbar = click_taskbar(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (event_taskbar == NULL)
|
||||
return;
|
||||
|
||||
// Find the task on the event's location
|
||||
Task *event_task = click_task(panel, e->xbutton.x, e->xbutton.y);
|
||||
|
||||
// If the event takes place on the same taskbar as the task being dragged
|
||||
if (&event_taskbar->area == task_drag->area.parent) {
|
||||
if (taskbar_sort_method != TASKBAR_NOSORT) {
|
||||
sort_tasks(event_taskbar);
|
||||
} else {
|
||||
// Swap the task_drag with the task on the event's location (if they differ)
|
||||
if (event_task && event_task != task_drag) {
|
||||
GList *drag_iter = g_list_find(event_taskbar->area.children, task_drag);
|
||||
GList *task_iter = g_list_find(event_taskbar->area.children, event_task);
|
||||
if (drag_iter && task_iter) {
|
||||
gpointer temp = task_iter->data;
|
||||
task_iter->data = drag_iter->data;
|
||||
drag_iter->data = temp;
|
||||
event_taskbar->area.resize_needed = 1;
|
||||
schedule_panel_redraw();
|
||||
task_dragged = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // The event is on another taskbar than the task being dragged
|
||||
if (task_drag->desktop == ALL_DESKTOPS || taskbar_mode != MULTI_DESKTOP)
|
||||
return;
|
||||
|
||||
Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent;
|
||||
remove_area((Area *)task_drag);
|
||||
|
||||
if (event_taskbar->area.posx > drag_taskbar->area.posx || event_taskbar->area.posy > drag_taskbar->area.posy) {
|
||||
int i = (taskbarname_enabled) ? 1 : 0;
|
||||
event_taskbar->area.children = g_list_insert(event_taskbar->area.children, task_drag, i);
|
||||
} else
|
||||
event_taskbar->area.children = g_list_append(event_taskbar->area.children, task_drag);
|
||||
|
||||
// Move task to other desktop (but avoid the 'Window desktop changed' code in 'event_property_notify')
|
||||
task_drag->area.parent = &event_taskbar->area;
|
||||
task_drag->desktop = event_taskbar->desktop;
|
||||
|
||||
change_window_desktop(task_drag->win, event_taskbar->desktop);
|
||||
if (hide_task_diff_desktop)
|
||||
change_desktop(event_taskbar->desktop);
|
||||
|
||||
if (taskbar_sort_method != TASKBAR_NOSORT) {
|
||||
sort_tasks(event_taskbar);
|
||||
}
|
||||
|
||||
event_taskbar->area.resize_needed = 1;
|
||||
drag_taskbar->area.resize_needed = 1;
|
||||
task_dragged = 1;
|
||||
schedule_panel_redraw();
|
||||
panel->area.resize_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_mouse_release_event(XEvent *e)
|
||||
{
|
||||
Panel *panel = get_panel(e->xany.window);
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
if (wm_menu && !tint2_handles_click(panel, &e->xbutton)) {
|
||||
forward_click(e);
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
MouseAction action = TOGGLE_ICONIFY;
|
||||
switch (e->xbutton.button) {
|
||||
case 1:
|
||||
action = mouse_left;
|
||||
break;
|
||||
case 2:
|
||||
action = mouse_middle;
|
||||
break;
|
||||
case 3:
|
||||
action = mouse_right;
|
||||
break;
|
||||
case 4:
|
||||
action = mouse_scroll_up;
|
||||
break;
|
||||
case 5:
|
||||
action = mouse_scroll_down;
|
||||
break;
|
||||
case 6:
|
||||
action = mouse_tilt_left;
|
||||
break;
|
||||
case 7:
|
||||
action = mouse_tilt_right;
|
||||
break;
|
||||
}
|
||||
|
||||
Clock *clock = click_clock(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (clock) {
|
||||
clock_action(clock, e->xbutton.button, e->xbutton.x - clock->area.posx, e->xbutton.y - clock->area.posy, e->xbutton.time);
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BATTERY
|
||||
Battery *battery = click_battery(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (battery) {
|
||||
battery_action(battery, e->xbutton.button, e->xbutton.x - battery->area.posx, e->xbutton.y - battery->area.posy, e->xbutton.time);
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Execp *execp = click_execp(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (execp) {
|
||||
execp_action(execp, e->xbutton.button, e->xbutton.x - execp->area.posx, e->xbutton.y - execp->area.posy, e->xbutton.time);
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Button *button = click_button(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (button) {
|
||||
button_action(button, e->xbutton.button, e->xbutton.x - button->area.posx, e->xbutton.y - button->area.posy, e->xbutton.time);
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->xbutton.button == 1 && click_launcher(panel, e->xbutton.x, e->xbutton.y)) {
|
||||
LauncherIcon *icon = click_launcher_icon(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (icon) {
|
||||
launcher_action(icon, e, e->xbutton.x - icon->area.posx, e->xbutton.y - icon->area.posy);
|
||||
}
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Taskbar *taskbar;
|
||||
if (!(taskbar = click_taskbar(panel, e->xbutton.x, e->xbutton.y))) {
|
||||
// TODO: check better solution to keep window below
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
task_drag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// drag and drop task
|
||||
if (task_dragged) {
|
||||
task_drag = 0;
|
||||
task_dragged = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// switch desktop
|
||||
if (taskbar_mode == MULTI_DESKTOP) {
|
||||
gboolean diff_desktop = FALSE;
|
||||
if (taskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT &&
|
||||
action != DESKTOP_RIGHT) {
|
||||
diff_desktop = TRUE;
|
||||
change_desktop(taskbar->desktop);
|
||||
}
|
||||
Task *task = click_task(panel, e->xbutton.x, e->xbutton.y);
|
||||
if (task) {
|
||||
if (diff_desktop) {
|
||||
if (action == TOGGLE_ICONIFY) {
|
||||
if (!window_is_active(task->win))
|
||||
activate_window(task->win);
|
||||
} else {
|
||||
task_handle_mouse_event(task, action);
|
||||
}
|
||||
} else {
|
||||
task_handle_mouse_event(task, action);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
task_handle_mouse_event(click_task(panel, e->xbutton.x, e->xbutton.y), action);
|
||||
}
|
||||
|
||||
// to keep window below
|
||||
if (panel_layer == BOTTOM_LAYER)
|
||||
XLowerWindow(server.display, panel->main_win);
|
||||
}
|
||||
12
src/mouse_actions.h
Normal file
12
src/mouse_actions.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef MOUSE_ACTIONS_H
|
||||
#define MOUSE_ACTIONS_H
|
||||
|
||||
#include "panel.h"
|
||||
|
||||
gboolean tint2_handles_click(Panel *panel, XButtonEvent *e);
|
||||
|
||||
void handle_mouse_press_event(XEvent *e);
|
||||
void handle_mouse_move_event(XEvent *e);
|
||||
void handle_mouse_release_event(XEvent *e);
|
||||
|
||||
#endif
|
||||
98
src/panel.c
98
src/panel.c
@@ -20,6 +20,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -36,8 +38,6 @@
|
||||
|
||||
void panel_clear_background(void *obj);
|
||||
|
||||
int signal_pending;
|
||||
|
||||
MouseAction mouse_left;
|
||||
MouseAction mouse_middle;
|
||||
MouseAction mouse_right;
|
||||
@@ -148,6 +148,8 @@ void cleanup_panel()
|
||||
cleanup_freespace(p);
|
||||
}
|
||||
|
||||
free_icon_themes();
|
||||
|
||||
free(panel_items_order);
|
||||
panel_items_order = NULL;
|
||||
free(panel_window_name);
|
||||
@@ -175,11 +177,11 @@ void init_panel()
|
||||
{
|
||||
if (panel_config.monitor > (server.num_monitors - 1)) {
|
||||
// server.num_monitors minimum value is 1 (see get_monitors())
|
||||
fprintf(stderr, "warning : monitor not found. tint2 default to all monitors.\n");
|
||||
fprintf(stderr, "tint2: warning : monitor not found. tint2 default to all monitors.\n");
|
||||
panel_config.monitor = 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "panel items: %s\n", panel_items_order);
|
||||
fprintf(stderr, "tint2: panel items: %s\n", panel_items_order);
|
||||
|
||||
icon_theme_wrapper = NULL;
|
||||
|
||||
@@ -207,7 +209,7 @@ void init_panel()
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"tint2 : nb monitor %d, nb monitor used %d, nb desktop %d\n",
|
||||
"tint2: nb monitors %d, nb monitors used %d, nb desktops %d\n",
|
||||
server.num_monitors,
|
||||
num_panels,
|
||||
server.num_desktops);
|
||||
@@ -287,7 +289,7 @@ void init_panel()
|
||||
XGCValues gcv;
|
||||
server.gc = XCreateGC(server.display, p->main_win, 0, &gcv);
|
||||
}
|
||||
// printf("panel %d : %d, %d, %d, %d\n", i, p->posx, p->posy, p->area.width, p->area.height);
|
||||
// fprintf(stderr, "tint2: panel %d : %d, %d, %d, %d\n", i, p->posx, p->posy, p->area.width, p->area.height);
|
||||
set_panel_properties(p);
|
||||
set_panel_background(p);
|
||||
if (!snapshot_path) {
|
||||
@@ -320,7 +322,7 @@ void panel_compute_size(Panel *panel)
|
||||
if (panel->fractional_height)
|
||||
panel->area.height = (server.monitors[panel->monitor].height - panel->marginy) * panel->area.height / 100;
|
||||
if (panel->area.bg->border.radius > panel->area.height / 2) {
|
||||
printf("panel_background_id rounded is too big... please fix your tint2rc\n");
|
||||
fprintf(stderr, "tint2: panel_background_id rounded is too big... please fix your tint2rc\n");
|
||||
g_array_append_val(backgrounds, *panel->area.bg);
|
||||
panel->area.bg = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||
panel->area.bg->border.radius = panel->area.height / 2;
|
||||
@@ -346,7 +348,7 @@ void panel_compute_size(Panel *panel)
|
||||
panel->area.width = old_panel_height;
|
||||
|
||||
if (panel->area.bg->border.radius > panel->area.width / 2) {
|
||||
printf("panel_background_id rounded is too big... please fix your tint2rc\n");
|
||||
fprintf(stderr, "tint2: panel_background_id rounded is too big... please fix your tint2rc\n");
|
||||
g_array_append_val(backgrounds, *panel->area.bg);
|
||||
panel->area.bg = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||
panel->area.bg->border.radius = panel->area.width / 2;
|
||||
@@ -399,7 +401,7 @@ void panel_compute_position(Panel *panel)
|
||||
panel->hidden_width = panel->area.width - diff;
|
||||
panel->hidden_height = panel->area.height;
|
||||
}
|
||||
// printf("panel : posx %d, posy %d, width %d, height %d\n", panel->posx, panel->posy, panel->area.width,
|
||||
// fprintf(stderr, "tint2: panel : posx %d, posy %d, width %d, height %d\n", panel->posx, panel->posy, panel->area.width,
|
||||
// panel->area.height);
|
||||
}
|
||||
|
||||
@@ -414,7 +416,7 @@ gboolean resize_panel(void *obj)
|
||||
Panel *panel = (Panel *)obj;
|
||||
relayout_with_constraint(&panel->area, 0);
|
||||
|
||||
// printf("resize_panel\n");
|
||||
// fprintf(stderr, "tint2: resize_panel\n");
|
||||
if (taskbar_mode != MULTI_DESKTOP && taskbar_enabled) {
|
||||
// propagate width/height on hidden taskbar
|
||||
int width = panel->taskbar[server.desktop].area.width;
|
||||
@@ -551,7 +553,7 @@ void update_strut(Panel *p)
|
||||
long struts[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
if (panel_horizontal) {
|
||||
int height = p->area.height + p->marginy;
|
||||
if (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && panel_autohide))
|
||||
if (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && panel_autohide && p->is_hidden))
|
||||
height = p->hidden_height;
|
||||
if (panel_position & TOP) {
|
||||
struts[2] = height + monitor.y;
|
||||
@@ -566,7 +568,7 @@ void update_strut(Panel *p)
|
||||
}
|
||||
} else {
|
||||
int width = p->area.width + p->marginx;
|
||||
if (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && panel_autohide))
|
||||
if (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && panel_autohide && p->is_hidden))
|
||||
width = p->hidden_width;
|
||||
if (panel_position & LEFT) {
|
||||
struts[0] = width + monitor.x;
|
||||
@@ -814,15 +816,24 @@ void set_panel_properties(Panel *p)
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
long pid = getpid();
|
||||
XChangeProperty(server.display,
|
||||
p->main_win,
|
||||
server.atom._NET_WM_PID,
|
||||
XA_CARDINAL,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&pid,
|
||||
1);
|
||||
|
||||
// Dock
|
||||
long val = server.atom._NET_WM_WINDOW_TYPE_DOCK;
|
||||
XChangeProperty(server.display,
|
||||
p->main_win,
|
||||
server.atom._NET_WM_WINDOW_TYPE,
|
||||
XA_ATOM,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&val,
|
||||
(unsigned char *)&server.atom._NET_WM_WINDOW_TYPE_DOCK,
|
||||
1);
|
||||
|
||||
place_panel_all_desktops(p);
|
||||
@@ -1135,6 +1146,63 @@ void _schedule_panel_redraw(const char *file, const char *function, const int li
|
||||
{
|
||||
panel_refresh = TRUE;
|
||||
if (debug_fps) {
|
||||
fprintf(stderr, YELLOW "%s %s %d: triggering panel redraw" RESET "\n", file, function, line);
|
||||
fprintf(stderr, YELLOW "tint2: %s %s %d: triggering panel redraw" RESET "\n", file, function, line);
|
||||
}
|
||||
}
|
||||
|
||||
void save_panel_screenshot(const Panel *panel, const char *path)
|
||||
{
|
||||
imlib_context_set_drawable(panel->temp_pmap);
|
||||
Imlib_Image img = imlib_create_image_from_drawable(0, 0, 0, panel->area.width, panel->area.height, 1);
|
||||
|
||||
if (!img) {
|
||||
XImage *ximg =
|
||||
XGetImage(server.display, panel->temp_pmap, 0, 0, panel->area.width, panel->area.height, AllPlanes, ZPixmap);
|
||||
|
||||
if (ximg) {
|
||||
DATA32 *pixels = (DATA32 *)calloc(panel->area.width * panel->area.height, sizeof(DATA32));
|
||||
for (int x = 0; x < panel->area.width; x++) {
|
||||
for (int y = 0; y < panel->area.height; y++) {
|
||||
DATA32 xpixel = XGetPixel(ximg, x, y);
|
||||
|
||||
DATA32 r = (xpixel >> 16) & 0xff;
|
||||
DATA32 g = (xpixel >> 8) & 0xff;
|
||||
DATA32 b = (xpixel >> 0) & 0xff;
|
||||
DATA32 a = 0x0;
|
||||
|
||||
DATA32 argb = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
pixels[y * panel->area.width + x] = argb;
|
||||
}
|
||||
}
|
||||
XDestroyImage(ximg);
|
||||
img = imlib_create_image_using_data(panel->area.width, panel->area.height, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
if (img) {
|
||||
imlib_context_set_image(img);
|
||||
if (!panel_horizontal) {
|
||||
// rotate 90° vertical panel
|
||||
imlib_image_flip_horizontal();
|
||||
imlib_image_flip_diagonal();
|
||||
}
|
||||
imlib_save_image(path);
|
||||
imlib_free_image();
|
||||
}
|
||||
}
|
||||
|
||||
void save_screenshot(const char *path)
|
||||
{
|
||||
Panel *panel = &panels[0];
|
||||
|
||||
if (panel->area.width > server.monitors[0].width)
|
||||
panel->area.width = server.monitors[0].width;
|
||||
|
||||
panel->temp_pmap =
|
||||
XCreatePixmap(server.display, server.root_win, panel->area.width, panel->area.height, server.depth);
|
||||
render_panel(panel);
|
||||
|
||||
XSync(server.display, False);
|
||||
|
||||
save_panel_screenshot(panel, path);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "battery.h"
|
||||
#endif
|
||||
|
||||
extern int signal_pending;
|
||||
// --------------------------------------------------
|
||||
// mouse events
|
||||
extern MouseAction mouse_left;
|
||||
@@ -93,6 +92,7 @@ extern XSettingsClient *xsettings_client;
|
||||
extern gboolean startup_notifications;
|
||||
extern gboolean debug_geometry;
|
||||
extern gboolean debug_fps;
|
||||
extern double tracing_fps_threshold;
|
||||
extern gboolean debug_frames;
|
||||
|
||||
typedef struct Panel {
|
||||
@@ -207,4 +207,7 @@ void default_font_changed();
|
||||
void free_icon(Imlib_Image icon);
|
||||
Imlib_Image scale_icon(Imlib_Image original, int icon_size);
|
||||
|
||||
void save_screenshot(const char *path);
|
||||
void save_panel_screenshot(const Panel *panel, const char *path);
|
||||
|
||||
#endif
|
||||
|
||||
110
src/server.c
110
src/server.c
@@ -18,21 +18,24 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "server.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "server.h"
|
||||
#include "signals.h"
|
||||
#include "window.h"
|
||||
|
||||
Server server;
|
||||
|
||||
gboolean primary_monitor_first = FALSE;
|
||||
|
||||
void server_catch_error(Display *d, XErrorEvent *ev)
|
||||
{
|
||||
}
|
||||
@@ -120,6 +123,14 @@ void server_init_atoms()
|
||||
server.atom.TARGETS = XInternAtom(server.display, "TARGETS", False);
|
||||
}
|
||||
|
||||
const char *GetAtomName(Display *disp, Atom a)
|
||||
{
|
||||
if (a == None)
|
||||
return "None";
|
||||
else
|
||||
return XGetAtomName(disp, a);
|
||||
}
|
||||
|
||||
void cleanup_server()
|
||||
{
|
||||
if (server.colormap)
|
||||
@@ -250,7 +261,7 @@ void get_root_pixmap()
|
||||
server.root_pmap = ret;
|
||||
|
||||
if (server.root_pmap == None) {
|
||||
fprintf(stderr, "tint2 : pixmap background detection failed\n");
|
||||
fprintf(stderr, "tint2: pixmap background detection failed\n");
|
||||
} else {
|
||||
XGCValues gcv;
|
||||
gcv.ts_x_origin = 0;
|
||||
@@ -268,13 +279,6 @@ int compare_monitor_pos(const void *monitor1, const void *monitor2)
|
||||
const Monitor *m1 = (const Monitor *)monitor1;
|
||||
const Monitor *m2 = (const Monitor *)monitor2;
|
||||
|
||||
if (primary_monitor_first) {
|
||||
if (m1->primary && !m2->primary)
|
||||
return -1;
|
||||
if (!m1->primary && m2->primary)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (m1->x < m2->x) {
|
||||
return -1;
|
||||
} else if (m1->x > m2->x) {
|
||||
@@ -317,14 +321,14 @@ void get_monitors()
|
||||
|
||||
if (res && res->ncrtc >= num_monitors) {
|
||||
// use xrandr to identify monitors (does not work with proprietery nvidia drivers)
|
||||
printf("xRandr: Found crtc's: %d\n", res->ncrtc);
|
||||
fprintf(stderr, "tint2: xRandr: Found crtc's: %d\n", res->ncrtc);
|
||||
server.monitors = calloc(res->ncrtc, sizeof(Monitor));
|
||||
num_monitors = 0;
|
||||
for (int i = 0; i < res->ncrtc; ++i) {
|
||||
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(server.display, res, res->crtcs[i]);
|
||||
// Ignore empty crtc
|
||||
if (!crtc_info->width || !crtc_info->height) {
|
||||
printf("xRandr: crtc %d seems disabled\n", i);
|
||||
fprintf(stderr, "tint2: xRandr: crtc %d seems disabled\n", i);
|
||||
XRRFreeCrtcInfo(crtc_info);
|
||||
continue;
|
||||
}
|
||||
@@ -337,7 +341,7 @@ void get_monitors()
|
||||
server.monitors[i_monitor].names = calloc((crtc_info->noutput + 1), sizeof(gchar *));
|
||||
for (int j = 0; j < crtc_info->noutput; ++j) {
|
||||
XRROutputInfo *output_info = XRRGetOutputInfo(server.display, res, crtc_info->outputs[j]);
|
||||
printf("xRandr: Linking output %s with crtc %d\n", output_info->name, i);
|
||||
fprintf(stderr, "tint2: xRandr: Linking output %s with crtc %d\n", output_info->name, i);
|
||||
server.monitors[i_monitor].names[j] = g_strdup(output_info->name);
|
||||
XRRFreeOutputInfo(output_info);
|
||||
server.monitors[i_monitor].primary = crtc_info->outputs[j] == primary_output;
|
||||
@@ -394,7 +398,7 @@ void get_monitors()
|
||||
|
||||
void print_monitors()
|
||||
{
|
||||
fprintf(stderr, "Number of monitors: %d\n", server.num_monitors);
|
||||
fprintf(stderr, "tint2: Number of monitors: %d\n", server.num_monitors);
|
||||
for (int i = 0; i < server.num_monitors; i++) {
|
||||
fprintf(stderr,
|
||||
"Monitor %d: x = %d, y = %d, w = %d, h = %d\n",
|
||||
@@ -516,10 +520,10 @@ int get_current_desktop()
|
||||
|
||||
int ncols = x_screen_width / work_area_width;
|
||||
|
||||
// fprintf(stderr, "\n");
|
||||
// fprintf(stderr, "Work area size: %d x %d\n", work_area_width, work_area_height);
|
||||
// fprintf(stderr, "Viewport pos: %d x %d\n", viewport_x, viewport_y);
|
||||
// fprintf(stderr, "Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x / work_area_width);
|
||||
// fprintf(stderr, "tint2: \n");
|
||||
// fprintf(stderr, "tint2: Work area size: %d x %d\n", work_area_width, work_area_height);
|
||||
// fprintf(stderr, "tint2: Viewport pos: %d x %d\n", viewport_x, viewport_y);
|
||||
// fprintf(stderr, "tint2: Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x / work_area_width);
|
||||
|
||||
int result = (viewport_y / work_area_height) * ncols + viewport_x / work_area_width;
|
||||
return MAX(0, MIN(server.num_desktops - 1, result));
|
||||
@@ -550,7 +554,7 @@ void get_desktops()
|
||||
}
|
||||
if (server.num_desktops == 0) {
|
||||
server.num_desktops = 1;
|
||||
fprintf(stderr, "warning : WM doesn't respect NETWM specs. tint2 default to 1 desktop.\n");
|
||||
fprintf(stderr, "tint2: warning : WM doesn't respect NETWM specs. tint2 default to 1 desktop.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,15 +598,77 @@ void server_init_visual()
|
||||
|
||||
server.real_transparency = TRUE;
|
||||
server.depth = 32;
|
||||
printf("real transparency on... depth: %d\n", server.depth);
|
||||
fprintf(stderr, "tint2: real transparency on... depth: %d\n", server.depth);
|
||||
server.colormap = XCreateColormap(server.display, server.root_win, visual, AllocNone);
|
||||
server.visual = visual;
|
||||
} else {
|
||||
// no composite manager or snapshot mode => fake transparency
|
||||
server.real_transparency = FALSE;
|
||||
server.depth = DefaultDepth(server.display, server.screen);
|
||||
printf("real transparency off.... depth: %d\n", server.depth);
|
||||
fprintf(stderr, "tint2: real transparency off.... depth: %d\n", server.depth);
|
||||
server.colormap = DefaultColormap(server.display, server.screen);
|
||||
server.visual = DefaultVisual(server.display, server.screen);
|
||||
}
|
||||
}
|
||||
|
||||
void server_init_xdamage()
|
||||
{
|
||||
XDamageQueryExtension(server.display, &server.xdamage_event_type, &server.xdamage_event_error_type);
|
||||
server.xdamage_event_type += XDamageNotify;
|
||||
server.xdamage_event_error_type += XDamageNotify;
|
||||
}
|
||||
|
||||
// Forward mouse click to the desktop window
|
||||
void forward_click(XEvent *e)
|
||||
{
|
||||
// forward the click to the desktop window (thanks conky)
|
||||
XUngrabPointer(server.display, e->xbutton.time);
|
||||
e->xbutton.window = server.root_win;
|
||||
// icewm doesn't open under the mouse.
|
||||
// and xfce doesn't open at all.
|
||||
e->xbutton.x = e->xbutton.x_root;
|
||||
e->xbutton.y = e->xbutton.y_root;
|
||||
// fprintf(stderr, "tint2: **** %d, %d\n", e->xbutton.x, e->xbutton.y);
|
||||
// XSetInputFocus(server.display, e->xbutton.window, RevertToParent, e->xbutton.time);
|
||||
XSendEvent(server.display, e->xbutton.window, False, ButtonPressMask, e);
|
||||
}
|
||||
|
||||
void handle_crash(const char *reason)
|
||||
{
|
||||
#ifndef DISABLE_BACKTRACE
|
||||
char path[4096];
|
||||
sprintf(path, "%s/.tint2-crash.log", get_home_dir());
|
||||
int log_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
log_string(log_fd, RED "tint2: crashed, reason: ");
|
||||
log_string(log_fd, reason);
|
||||
log_string(log_fd, RESET "\n");
|
||||
dump_backtrace(log_fd);
|
||||
log_string(log_fd, RED "Please create a bug report with this log output." RESET "\n");
|
||||
close(log_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void x11_io_error(Display *display)
|
||||
{
|
||||
handle_crash("X11 I/O error");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SN
|
||||
static int error_trap_depth = 0;
|
||||
|
||||
void error_trap_push(SnDisplay *display, Display *xdisplay)
|
||||
{
|
||||
++error_trap_depth;
|
||||
}
|
||||
|
||||
void error_trap_pop(SnDisplay *display, Display *xdisplay)
|
||||
{
|
||||
if (error_trap_depth == 0) {
|
||||
fprintf(stderr, "tint2: Error trap underflow!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
XSync(xdisplay, False); /* get all errors out of the queue */
|
||||
--error_trap_depth;
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
|
||||
24
src/server.h
24
src/server.h
@@ -93,6 +93,15 @@ typedef struct Global_atom {
|
||||
Atom TARGETS;
|
||||
} Global_atom;
|
||||
|
||||
typedef struct Property {
|
||||
unsigned char *data;
|
||||
int format, nitems;
|
||||
Atom type;
|
||||
} Property;
|
||||
|
||||
// Returns the name of an Atom as string. Do not free the string.
|
||||
const char *GetAtomName(Display *disp, Atom a);
|
||||
|
||||
typedef struct Monitor {
|
||||
int x;
|
||||
int y;
|
||||
@@ -111,6 +120,7 @@ typedef struct Viewport {
|
||||
|
||||
typedef struct Server {
|
||||
Display *display;
|
||||
int x11_fd;
|
||||
Window root_win;
|
||||
Window composite_manager;
|
||||
gboolean real_transparency;
|
||||
@@ -135,6 +145,8 @@ typedef struct Server {
|
||||
Colormap colormap;
|
||||
Colormap colormap32;
|
||||
Global_atom atom;
|
||||
int xdamage_event_type;
|
||||
int xdamage_event_error_type;
|
||||
#ifdef HAVE_SN
|
||||
SnDisplay *sn_display;
|
||||
GTree *pids;
|
||||
@@ -153,6 +165,10 @@ Atom server_get_atom(char *atom_name);
|
||||
void server_catch_error(Display *d, XErrorEvent *ev);
|
||||
void server_init_atoms();
|
||||
void server_init_visual();
|
||||
void server_init_xdamage();
|
||||
|
||||
void x11_io_error(Display *display);
|
||||
void handle_crash(const char *reason);
|
||||
|
||||
// detect root background
|
||||
void get_root_pixmap();
|
||||
@@ -167,4 +183,12 @@ GSList *get_desktop_names();
|
||||
int get_current_desktop();
|
||||
void change_desktop(int desktop);
|
||||
|
||||
// Forward mouse click to the desktop window
|
||||
void forward_click(XEvent *e);
|
||||
|
||||
#ifdef HAVE_SN
|
||||
void error_trap_push(SnDisplay *display, Display *xdisplay);
|
||||
void error_trap_pop(SnDisplay *display, Display *xdisplay);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
154
src/signals.c
Normal file
154
src/signals.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#ifdef HAVE_SN
|
||||
#include <libsn/sn.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "panel.h"
|
||||
#include "launcher.h"
|
||||
#include "server.h"
|
||||
#include "signals.h"
|
||||
|
||||
static sig_atomic_t signal_pending;
|
||||
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
// signal handler is light as it should be
|
||||
signal_pending = sig;
|
||||
}
|
||||
|
||||
void init_signals()
|
||||
{
|
||||
// Set signal handlers
|
||||
signal_pending = 0;
|
||||
|
||||
struct sigaction sa_chld = {.sa_handler = SIG_IGN};
|
||||
sigaction(SIGCHLD, &sa_chld, 0);
|
||||
|
||||
struct sigaction sa = {.sa_handler = signal_handler, .sa_flags = SA_RESTART};
|
||||
sigaction(SIGUSR1, &sa, 0);
|
||||
sigaction(SIGUSR2, &sa, 0);
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
sigaction(SIGTERM, &sa, 0);
|
||||
sigaction(SIGHUP, &sa, 0);
|
||||
|
||||
#ifdef BACKTRACE_ON_SIGNAL
|
||||
struct sigaction sa_crash = {.sa_handler = crash_handler};
|
||||
sigaction(SIGSEGV, &sa_crash, 0);
|
||||
sigaction(SIGFPE, &sa_crash, 0);
|
||||
sigaction(SIGPIPE, &sa_crash, 0);
|
||||
sigaction(SIGBUS, &sa_crash, 0);
|
||||
sigaction(SIGABRT, &sa_crash, 0);
|
||||
sigaction(SIGSYS, &sa_crash, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BACKTRACE_ON_SIGNAL
|
||||
void crash_handler(int sig)
|
||||
{
|
||||
handle_crash(signal_name(sig));
|
||||
struct sigaction sa = {.sa_handler = SIG_DFL};
|
||||
sigaction(sig, &sa, 0);
|
||||
raise(sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
int sigchild_pipe_valid = FALSE;
|
||||
int sigchild_pipe[2];
|
||||
|
||||
static void sigchld_handler(int sig)
|
||||
{
|
||||
if (!sigchild_pipe_valid)
|
||||
return;
|
||||
int savedErrno = errno;
|
||||
ssize_t unused = write(sigchild_pipe[1], "x", 1);
|
||||
(void)unused;
|
||||
fsync(sigchild_pipe[1]);
|
||||
errno = savedErrno;
|
||||
}
|
||||
|
||||
void sigchld_handler_async()
|
||||
{
|
||||
// Wait for all dead processes
|
||||
pid_t pid;
|
||||
int status;
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) {
|
||||
#ifdef HAVE_SN
|
||||
if (startup_notifications) {
|
||||
SnLauncherContext *ctx = (SnLauncherContext *)g_tree_lookup(server.pids, GINT_TO_POINTER(pid));
|
||||
if (ctx) {
|
||||
g_tree_remove(server.pids, GINT_TO_POINTER(pid));
|
||||
sn_launcher_context_complete(ctx);
|
||||
sn_launcher_context_unref(ctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (GList *l = panel_config.execp_list; l; l = l->next) {
|
||||
Execp *execp = (Execp *)l->data;
|
||||
if (g_tree_lookup(execp->backend->cmd_pids, GINT_TO_POINTER(pid)))
|
||||
execp_cmd_completed(execp, pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_sigchld_events()
|
||||
{
|
||||
if (sigchild_pipe_valid) {
|
||||
char buffer[1];
|
||||
while (read(sigchild_pipe[0], buffer, sizeof(buffer)) > 0) {
|
||||
sigchld_handler_async();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_signals_postconfig()
|
||||
{
|
||||
gboolean need_sigchld = FALSE;
|
||||
#ifdef HAVE_SN
|
||||
// Initialize startup-notification
|
||||
if (startup_notifications) {
|
||||
server.sn_display = sn_display_new(server.display, error_trap_push, error_trap_pop);
|
||||
server.pids = g_tree_new(cmp_ptr);
|
||||
need_sigchld = TRUE;
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
if (panel_config.execp_list)
|
||||
need_sigchld = TRUE;
|
||||
|
||||
if (need_sigchld) {
|
||||
// Setup a handler for child termination
|
||||
if (pipe(sigchild_pipe) != 0) {
|
||||
fprintf(stderr, "tint2: Creating pipe failed.\n");
|
||||
} else {
|
||||
fcntl(sigchild_pipe[0], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[0], F_GETFL));
|
||||
fcntl(sigchild_pipe[1], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[1], F_GETFL));
|
||||
sigchild_pipe_valid = 1;
|
||||
struct sigaction act = {.sa_handler = sigchld_handler, .sa_flags = SA_RESTART};
|
||||
if (sigaction(SIGCHLD, &act, 0)) {
|
||||
perror("sigaction");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emit_self_restart(const char *reason)
|
||||
{
|
||||
fprintf(stderr,
|
||||
YELLOW "%s %d: triggering tint2 restart, reason: %s" RESET "\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
reason);
|
||||
signal_pending = SIGUSR1;
|
||||
}
|
||||
|
||||
int get_signal_pending()
|
||||
{
|
||||
return signal_pending;
|
||||
}
|
||||
14
src/signals.h
Normal file
14
src/signals.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef SIGNALS_H
|
||||
#define SIGNALS_H
|
||||
|
||||
void init_signals();
|
||||
void init_signals_postconfig();
|
||||
void emit_self_restart(const char *reason);
|
||||
int get_signal_pending();
|
||||
|
||||
void handle_sigchld_events();
|
||||
|
||||
extern int sigchild_pipe_valid;
|
||||
extern int sigchild_pipe[2];
|
||||
|
||||
#endif
|
||||
@@ -114,10 +114,10 @@ void init_systray()
|
||||
return;
|
||||
|
||||
systray_composited = !server.disable_transparency && server.visual32 && server.colormap32;
|
||||
fprintf(stderr, "Systray composited rendering %s\n", systray_composited ? "on" : "off");
|
||||
fprintf(stderr, "tint2: Systray composited rendering %s\n", systray_composited ? "on" : "off");
|
||||
|
||||
if (!systray_composited) {
|
||||
fprintf(stderr, "systray_asb forced to 100 0 0\n");
|
||||
fprintf(stderr, "tint2: systray_asb forced to 100 0 0\n");
|
||||
systray.alpha = 100;
|
||||
systray.brightness = systray.saturation = 0;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ int systray_compute_desired_size(void *obj)
|
||||
gboolean resize_systray(void *obj)
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
|
||||
int size;
|
||||
systray_compute_geometry(&size);
|
||||
@@ -227,7 +227,7 @@ gboolean resize_systray(void *obj)
|
||||
void draw_systray(void *obj, cairo_t *c)
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, BLUE "[%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, BLUE "tint2: [%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
if (systray_composited) {
|
||||
if (render_background)
|
||||
XFreePixmap(server.display, render_background);
|
||||
@@ -252,7 +252,7 @@ void systray_dump_geometry(void *obj, int indent)
|
||||
{
|
||||
Systray *tray = (Systray *)obj;
|
||||
|
||||
fprintf(stderr, "%*sIcons:\n", indent, "");
|
||||
fprintf(stderr, "tint2: %*sIcons:\n", indent, "");
|
||||
indent += 2;
|
||||
for (GSList *l = tray->list_icons; l; l = l->next) {
|
||||
TrayWindow *traywin = (TrayWindow *)l->data;
|
||||
@@ -271,7 +271,7 @@ void systray_dump_geometry(void *obj, int indent)
|
||||
void on_change_systray(void *obj)
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
if (systray.icons_per_column == 0 || systray.icons_per_row == 0)
|
||||
return;
|
||||
|
||||
@@ -332,7 +332,7 @@ void on_change_systray(void *obj)
|
||||
unsigned int width, height, depth;
|
||||
Window root;
|
||||
if (!XGetGeometry(server.display, traywin->parent, &root, &xpos, &ypos, &width, &height, &border_width, &depth)) {
|
||||
fprintf(stderr, RED "Couldn't get geometry of window!" RESET "\n");
|
||||
fprintf(stderr, RED "tint2: Couldn't get geometry of window!" RESET "\n");
|
||||
}
|
||||
if (width != traywin->width || height != traywin->height || xpos != traywin->x || ypos != traywin->y) {
|
||||
if (systray_profile)
|
||||
@@ -358,7 +358,7 @@ void on_change_systray(void *obj)
|
||||
void start_net()
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
if (net_sel_win) {
|
||||
// protocol already started
|
||||
if (!systray_enabled)
|
||||
@@ -395,11 +395,11 @@ void start_net()
|
||||
&bytes_after,
|
||||
&prop);
|
||||
|
||||
fprintf(stderr, RED "tint2 : another systray is running" RESET);
|
||||
fprintf(stderr, RED "tint2: another systray is running, cannot use systray" RESET);
|
||||
if (ret == Success && prop) {
|
||||
pid = prop[1] * 256;
|
||||
pid += prop[0];
|
||||
fprintf(stderr, " pid=%d", pid);
|
||||
fprintf(stderr, "tint2: pid=%d", pid);
|
||||
}
|
||||
fprintf(stderr, RESET "\n");
|
||||
return;
|
||||
@@ -407,7 +407,7 @@ void start_net()
|
||||
|
||||
// init systray protocol
|
||||
net_sel_win = XCreateSimpleWindow(server.display, server.root_win, -1, -1, 1, 1, 0, 0, 0);
|
||||
fprintf(stderr, "systray window %ld\n", net_sel_win);
|
||||
fprintf(stderr, "tint2: systray window %ld\n", net_sel_win);
|
||||
|
||||
// v0.3 trayer specification. tint2 always horizontal.
|
||||
// Vertical panel will draw the systray horizontal.
|
||||
@@ -458,13 +458,13 @@ void start_net()
|
||||
XSetSelectionOwner(server.display, server.atom._NET_SYSTEM_TRAY_SCREEN, net_sel_win, CurrentTime);
|
||||
if (XGetSelectionOwner(server.display, server.atom._NET_SYSTEM_TRAY_SCREEN) != net_sel_win) {
|
||||
stop_net();
|
||||
fprintf(stderr, RED "tint2 : can't get systray manager" RESET "\n");
|
||||
fprintf(stderr, RED "tint2: cannot find systray manager" RESET "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, GREEN "tint2 : systray started" RESET "\n");
|
||||
fprintf(stderr, GREEN "tint2: systray started" RESET "\n");
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
XClientMessageEvent ev;
|
||||
ev.type = ClientMessage;
|
||||
ev.window = server.root_win;
|
||||
@@ -478,10 +478,10 @@ void start_net()
|
||||
XSendEvent(server.display, server.root_win, False, StructureNotifyMask, (XEvent *)&ev);
|
||||
}
|
||||
|
||||
void net_message(XClientMessageEvent *e)
|
||||
void handle_systray_event(XClientMessageEvent *e)
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
|
||||
Window win;
|
||||
unsigned long opcode = e->data.l[1];
|
||||
@@ -499,9 +499,9 @@ void net_message(XClientMessageEvent *e)
|
||||
|
||||
default:
|
||||
if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA)
|
||||
fprintf(stderr, "message from dockapp: %s\n", e->data.b);
|
||||
fprintf(stderr, "tint2: message from dockapp: %s\n", e->data.b);
|
||||
else
|
||||
fprintf(stderr, RED "SYSTEM_TRAY : unknown message type" RESET "\n");
|
||||
fprintf(stderr, RED "tint2: SYSTEM_TRAY : unknown message type" RESET "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -509,7 +509,7 @@ void net_message(XClientMessageEvent *e)
|
||||
void stop_net()
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
if (systray.list_icons) {
|
||||
// remove_icon change systray.list_icons
|
||||
while (systray.list_icons)
|
||||
@@ -529,10 +529,10 @@ gboolean error;
|
||||
int window_error_handler(Display *d, XErrorEvent *e)
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, RED "[%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, RED "tint2: [%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
error = TRUE;
|
||||
if (e->error_code != BadWindow) {
|
||||
fprintf(stderr, RED "systray: error code %d" RESET "\n", e->error_code);
|
||||
fprintf(stderr, RED "tint2: systray: error code %d" RESET "\n", e->error_code);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -564,18 +564,18 @@ static gint compare_traywindows(gconstpointer a, gconstpointer b)
|
||||
|
||||
void print_icons()
|
||||
{
|
||||
fprintf(stderr, "systray.list_icons: \n");
|
||||
fprintf(stderr, "tint2: systray.list_icons: \n");
|
||||
for (GSList *l = systray.list_icons; l; l = l->next) {
|
||||
TrayWindow *t = l->data;
|
||||
fprintf(stderr, "%s\n", t->name);
|
||||
fprintf(stderr, "tint2: %s\n", t->name);
|
||||
}
|
||||
fprintf(stderr, "systray.list_icons order: \n");
|
||||
fprintf(stderr, "tint2: systray.list_icons order: \n");
|
||||
for (GSList *l = systray.list_icons; l; l = l->next) {
|
||||
if (l->next) {
|
||||
TrayWindow *t = l->data;
|
||||
TrayWindow *u = l->next->data;
|
||||
int cmp = compare_traywindows(t, u);
|
||||
fprintf(stderr, "%s %s %s\n", t->name, cmp < 0 ? "<" : cmp == 0 ? "=" : ">", u->name);
|
||||
fprintf(stderr, "tint2: %s %s %s\n", t->name, cmp < 0 ? "<" : cmp == 0 ? "=" : ">", u->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -586,14 +586,14 @@ gboolean reject_icon(Window win)
|
||||
if (!systray_hide_name_regex) {
|
||||
systray_hide_name_regex = (regex_t *)calloc(1, sizeof(*systray_hide_name_regex));
|
||||
if (regcomp(systray_hide_name_regex, systray_hide_name_filter, 0) != 0) {
|
||||
fprintf(stderr, RED "Could not compile regex %s" RESET "\n", systray_hide_name_filter);
|
||||
fprintf(stderr, RED "tint2: Could not compile regex %s" RESET "\n", systray_hide_name_filter);
|
||||
free_and_null(systray_hide_name_regex);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
char *name = get_window_name(win);
|
||||
if (regexec(systray_hide_name_regex, name, 0, NULL, 0) == 0) {
|
||||
fprintf(stderr, GREEN "Filtering out systray icon '%s'" RESET "\n", name);
|
||||
fprintf(stderr, GREEN "tint2: Filtering out systray icon '%s'" RESET "\n", name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -623,7 +623,7 @@ gboolean add_icon(Window win)
|
||||
|
||||
char *name = get_window_name(win);
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d win = %lu (%s)\n", profiling_get_time(), __FUNCTION__, __LINE__, win, name);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d win = %lu (%s)\n", profiling_get_time(), __FUNCTION__, __LINE__, win, name);
|
||||
Panel *panel = systray.area.panel;
|
||||
|
||||
// Get the process ID of the application that created the window
|
||||
@@ -655,7 +655,7 @@ gboolean add_icon(Window win)
|
||||
// Create the parent window that will embed the icon
|
||||
XWindowAttributes attr;
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XGetWindowAttributes(server.display, win = %ld, &attr)\n", win);
|
||||
fprintf(stderr, "tint2: XGetWindowAttributes(server.display, win = %ld, &attr)\n", win);
|
||||
if (XGetWindowAttributes(server.display, win, &attr) == False) {
|
||||
free(name);
|
||||
XSelectInput(server.display, win, NoEventMask);
|
||||
@@ -706,7 +706,7 @@ gboolean add_icon(Window win)
|
||||
}
|
||||
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XCreateWindow(...)\n");
|
||||
fprintf(stderr, "tint2: XCreateWindow(...)\n");
|
||||
Window parent = XCreateWindow(server.display,
|
||||
panel->main_win,
|
||||
0,
|
||||
@@ -743,12 +743,12 @@ gboolean add_icon(Window win)
|
||||
|
||||
if (!panel->is_hidden) {
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XMapRaised(server.display, traywin->parent)\n");
|
||||
fprintf(stderr, "tint2: XMapRaised(server.display, traywin->parent)\n");
|
||||
XMapRaised(server.display, traywin->parent);
|
||||
}
|
||||
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "[%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, "tint2: [%f] %s:%d\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
|
||||
// Resize and redraw the systray
|
||||
if (systray_profile)
|
||||
@@ -808,7 +808,7 @@ gboolean reparent_icon(TrayWindow *traywin)
|
||||
e.xclient.data.l[3] = traywin->parent;
|
||||
e.xclient.data.l[4] = 0;
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XSendEvent(server.display, traywin->win, False, NoEventMask, &e)\n");
|
||||
fprintf(stderr, "tint2: XSendEvent(server.display, traywin->win, False, NoEventMask, &e)\n");
|
||||
XSendEvent(server.display, traywin->win, False, NoEventMask, &e);
|
||||
}
|
||||
|
||||
@@ -859,62 +859,13 @@ gboolean embed_icon(TrayWindow *traywin)
|
||||
error = FALSE;
|
||||
XErrorHandler old = XSetErrorHandler(window_error_handler);
|
||||
|
||||
if (0) {
|
||||
Atom acttype;
|
||||
int actfmt;
|
||||
unsigned long nbitem, bytes;
|
||||
unsigned long *data = 0;
|
||||
int ret;
|
||||
|
||||
if (systray_profile)
|
||||
fprintf(stderr,
|
||||
"XGetWindowProperty(server.display, traywin->win, server.atom._XEMBED_INFO, 0, 2, False, "
|
||||
"server.atom._XEMBED_INFO, &acttype, &actfmt, &nbitem, &bytes, &data)\n");
|
||||
ret = XGetWindowProperty(server.display,
|
||||
traywin->win,
|
||||
server.atom._XEMBED_INFO,
|
||||
0,
|
||||
2,
|
||||
False,
|
||||
server.atom._XEMBED_INFO,
|
||||
&acttype,
|
||||
&actfmt,
|
||||
&nbitem,
|
||||
&bytes,
|
||||
(unsigned char **)&data);
|
||||
if (ret == Success) {
|
||||
if (data) {
|
||||
if (nbitem >= 2) {
|
||||
int hide = ((data[1] & XEMBED_MAPPED) == 0);
|
||||
if (hide) {
|
||||
// In theory we have to check the embedding with this and remove icons that refuse embedding.
|
||||
// In practice we have no idea when the other application processes the event and accepts the
|
||||
// embed so we cannot check now without a race.
|
||||
// Race can be triggered with PyGtk(2) apps.
|
||||
// We could defer this for later (if we set PropertyChangeMask in XSelectInput we get notified)
|
||||
// but for some reason it breaks transparency for Qt icons. So we don't.
|
||||
// fprintf(stderr, RED "tint2: window refused embedding" RESET "\n");
|
||||
// remove_icon(traywin);
|
||||
// XFree(data);
|
||||
// return FALSE;
|
||||
}
|
||||
}
|
||||
XFree(data);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, RED "tint2 : xembed error" RESET "\n");
|
||||
remove_icon(traywin);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect rendering when using compositing
|
||||
if (systray_composited) {
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XDamageCreate(server.display, traywin->parent, XDamageReportRawRectangles)\n");
|
||||
fprintf(stderr, "tint2: XDamageCreate(server.display, traywin->parent, XDamageReportRawRectangles)\n");
|
||||
traywin->damage = XDamageCreate(server.display, traywin->parent, XDamageReportRawRectangles);
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XCompositeRedirectWindow(server.display, traywin->parent, CompositeRedirectManual)\n");
|
||||
fprintf(stderr, "tint2: XCompositeRedirectWindow(server.display, traywin->parent, CompositeRedirectManual)\n");
|
||||
XCompositeRedirectWindow(server.display, traywin->parent, CompositeRedirectManual);
|
||||
}
|
||||
|
||||
@@ -922,16 +873,16 @@ gboolean embed_icon(TrayWindow *traywin)
|
||||
|
||||
// Make the icon visible
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XMapWindow(server.display, traywin->win)\n");
|
||||
fprintf(stderr, "tint2: XMapWindow(server.display, traywin->win)\n");
|
||||
XMapWindow(server.display, traywin->win);
|
||||
if (!panel->is_hidden) {
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XMapRaised(server.display, traywin->parent)\n");
|
||||
fprintf(stderr, "tint2: XMapRaised(server.display, traywin->parent)\n");
|
||||
XMapRaised(server.display, traywin->parent);
|
||||
}
|
||||
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "XSync(server.display, False)\n");
|
||||
fprintf(stderr, "tint2: XSync(server.display, False)\n");
|
||||
XSync(server.display, False);
|
||||
XSetErrorHandler(old);
|
||||
if (error != FALSE) {
|
||||
@@ -974,7 +925,7 @@ void remove_icon(TrayWindow *traywin)
|
||||
|
||||
// remove from our list
|
||||
systray.list_icons = g_slist_remove(systray.list_icons, traywin);
|
||||
fprintf(stderr, YELLOW "remove_icon: %lu (%s)" RESET "\n", traywin->win, traywin->name);
|
||||
fprintf(stderr, YELLOW "tint2: remove_icon: %lu (%s)" RESET "\n", traywin->win, traywin->name);
|
||||
|
||||
XSelectInput(server.display, traywin->win, NoEventMask);
|
||||
if (traywin->damage)
|
||||
@@ -1328,7 +1279,7 @@ void systray_render_icon_composited(void *t)
|
||||
} else if (traywin->depth == 32) {
|
||||
f = XRenderFindStandardFormat(server.display, PictStandardARGB32);
|
||||
} else {
|
||||
fprintf(stderr, RED "Strange tray icon found with depth: %d" RESET "\n", traywin->depth);
|
||||
fprintf(stderr, RED "tint2: Strange tray icon found with depth: %d" RESET "\n", traywin->depth);
|
||||
XFreePixmap(server.display, tmp_pmap);
|
||||
return;
|
||||
}
|
||||
@@ -1498,7 +1449,7 @@ void systray_render_icon(void *t)
|
||||
Window root;
|
||||
if (!XGetGeometry(server.display, traywin->win, &root, &xpos, &ypos, &width, &height, &border_width, &depth)) {
|
||||
stop_timeout(traywin->render_timeout);
|
||||
if (!traywin->resize_timeout)
|
||||
if (!traywin->render_timeout)
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon, traywin, &traywin->render_timeout);
|
||||
systray_render_icon_from_image(traywin);
|
||||
@@ -1507,7 +1458,7 @@ void systray_render_icon(void *t)
|
||||
} else {
|
||||
if (xpos != 0 || ypos != 0 || width != traywin->width || height != traywin->height) {
|
||||
stop_timeout(traywin->render_timeout);
|
||||
if (!traywin->resize_timeout)
|
||||
if (!traywin->render_timeout)
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon, traywin, &traywin->render_timeout);
|
||||
systray_render_icon_from_image(traywin);
|
||||
@@ -1527,7 +1478,7 @@ void systray_render_icon(void *t)
|
||||
}
|
||||
|
||||
if (systray_profile)
|
||||
fprintf(stderr, "rendering tray icon\n");
|
||||
fprintf(stderr, "tint2: rendering tray icon\n");
|
||||
|
||||
if (systray_composited) {
|
||||
systray_render_icon_composited(traywin);
|
||||
@@ -1549,7 +1500,7 @@ void systray_render_icon(void *t)
|
||||
void refresh_systray_icons()
|
||||
{
|
||||
if (systray_profile)
|
||||
fprintf(stderr, BLUE "[%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
fprintf(stderr, BLUE "tint2: [%f] %s:%d" RESET "\n", profiling_get_time(), __FUNCTION__, __LINE__);
|
||||
TrayWindow *traywin;
|
||||
GSList *l;
|
||||
for (l = systray.list_icons; l; l = l->next) {
|
||||
|
||||
@@ -96,7 +96,7 @@ gboolean systray_on_monitor(int i_monitor, int num_panels);
|
||||
// many tray icon doesn't manage stop/restart of the systray manager
|
||||
void start_net();
|
||||
void stop_net();
|
||||
void net_message(XClientMessageEvent *e);
|
||||
void handle_systray_event(XClientMessageEvent *e);
|
||||
|
||||
gboolean add_icon(Window id);
|
||||
gboolean reparent_icon(TrayWindow *traywin);
|
||||
|
||||
@@ -93,9 +93,9 @@ Task *add_task(Window win)
|
||||
(int)win,
|
||||
task_template.title ? task_template.title : "null");
|
||||
|
||||
// fprintf(stderr, "%s %d: win = %ld, task = %s\n", __FUNCTION__, __LINE__, win, task_template.title ?
|
||||
// fprintf(stderr, "tint2: %s %d: win = %ld, task = %s\n", __FUNCTION__, __LINE__, win, task_template.title ?
|
||||
// task_template.title : "??");
|
||||
// fprintf(stderr, "new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor);
|
||||
// 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++) {
|
||||
@@ -118,7 +118,7 @@ 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, "%s %d: win = %ld hiding task: another desktop\n", __FUNCTION__, __LINE__, win);
|
||||
// fprintf(stderr, "tint2: %s %d: win = %ld hiding task: another desktop\n", __FUNCTION__, __LINE__, win);
|
||||
task_instance->area.on_screen = always_show_all_desktop_tasks;
|
||||
}
|
||||
task_instance->title = task_template.title;
|
||||
@@ -158,26 +158,10 @@ Task *add_task(Window win)
|
||||
return (Task *)g_ptr_array_index(task_buttons, 0);
|
||||
}
|
||||
|
||||
void remove_task(Task *task)
|
||||
void task_remove_icon(Task *task)
|
||||
{
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
// fprintf(stderr, "%s %d: win = %ld, task = %s\n", __FUNCTION__, __LINE__, task->win, task->title ? task->title :
|
||||
// "??");
|
||||
|
||||
if (taskbar_mode == MULTI_DESKTOP) {
|
||||
Panel *panel = task->area.panel;
|
||||
panel->area.resize_needed = 1;
|
||||
}
|
||||
|
||||
Window win = task->win;
|
||||
|
||||
// free title and icon just for the first task
|
||||
// even with task_on_all_desktop and with task_on_all_panel
|
||||
// printf("remove_task %s %d\n", task->title, task->desktop);
|
||||
if (task->title)
|
||||
free(task->title);
|
||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||
if (task->icon[k]) {
|
||||
imlib_context_set_image(task->icon[k]);
|
||||
@@ -195,6 +179,29 @@ void remove_task(Task *task)
|
||||
task->icon_press[k] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove_task(Task *task)
|
||||
{
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
// fprintf(stderr, "tint2: %s %d: win = %ld, task = %s\n", __FUNCTION__, __LINE__, task->win, task->title ? task->title :
|
||||
// "??");
|
||||
|
||||
if (taskbar_mode == MULTI_DESKTOP) {
|
||||
Panel *panel = task->area.panel;
|
||||
panel->area.resize_needed = 1;
|
||||
}
|
||||
|
||||
Window win = task->win;
|
||||
|
||||
// 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);
|
||||
task_remove_icon(task);
|
||||
|
||||
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
||||
for (int i = 0; i < task_buttons->len; ++i) {
|
||||
@@ -265,36 +272,32 @@ void task_update_icon(Task *task)
|
||||
if (!panel->g_task.has_icon)
|
||||
return;
|
||||
|
||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||
if (task->icon[k]) {
|
||||
imlib_context_set_image(task->icon[k]);
|
||||
imlib_free_image();
|
||||
task->icon[k] = 0;
|
||||
}
|
||||
}
|
||||
task_remove_icon(task);
|
||||
|
||||
Imlib_Image img = NULL;
|
||||
|
||||
if (!img) {
|
||||
int i;
|
||||
gulong *data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &i);
|
||||
int len;
|
||||
gulong *data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &len);
|
||||
if (data) {
|
||||
// get ARGB icon
|
||||
int w, h;
|
||||
gulong *tmp_data;
|
||||
|
||||
tmp_data = get_best_icon(data, get_icon_count(data, i), i, &w, &h, panel->g_task.icon_size1);
|
||||
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",
|
||||
__FUNCTION__,
|
||||
w,
|
||||
h,
|
||||
task->title ? task->title : "task");
|
||||
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);
|
||||
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",
|
||||
__FUNCTION__,
|
||||
w,
|
||||
h,
|
||||
task->title ? task->title : "task");
|
||||
}
|
||||
}
|
||||
XFree(data);
|
||||
}
|
||||
}
|
||||
@@ -327,8 +330,6 @@ void task_update_icon(Task *task)
|
||||
if (img == NULL) {
|
||||
imlib_context_set_image(default_icon);
|
||||
img = imlib_clone_image();
|
||||
if (0)
|
||||
fprintf(stderr, "%s: Using default icon for %s\n", __FUNCTION__, task->title ? task->title : "task");
|
||||
}
|
||||
|
||||
// transform icons
|
||||
@@ -590,7 +591,7 @@ void reset_active_task()
|
||||
}
|
||||
|
||||
Window w1 = get_active_window();
|
||||
// printf("Change active task %ld\n", w1);
|
||||
// fprintf(stderr, "tint2: Change active task %ld\n", w1);
|
||||
|
||||
if (w1) {
|
||||
if (!get_task_buttons(w1)) {
|
||||
@@ -621,7 +622,7 @@ void set_task_state(Task *task, TaskState state)
|
||||
}
|
||||
}
|
||||
|
||||
if (task->current_state != state || hide_task_diff_monitor) {
|
||||
if (task->current_state != state || hide_task_diff_monitor || hide_task_diff_desktop) {
|
||||
GPtrArray *task_buttons = get_task_buttons(task->win);
|
||||
if (task_buttons) {
|
||||
for (int i = 0; i < task_buttons->len; ++i) {
|
||||
@@ -645,6 +646,10 @@ void set_task_state(Task *task, TaskState state)
|
||||
hide = TRUE;
|
||||
}
|
||||
}
|
||||
if (hide_task_diff_desktop) {
|
||||
if (taskbar->desktop != server.desktop)
|
||||
hide = TRUE;
|
||||
}
|
||||
if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor &&
|
||||
(hide_task_diff_monitor || num_panels > 1)) {
|
||||
hide = TRUE;
|
||||
@@ -712,3 +717,76 @@ void del_urgent(Task *task)
|
||||
urgent_timeout = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void task_handle_mouse_event(Task *task, MouseAction action)
|
||||
{
|
||||
if (!task)
|
||||
return;
|
||||
switch (action) {
|
||||
case NONE:
|
||||
break;
|
||||
case CLOSE:
|
||||
close_window(task->win);
|
||||
break;
|
||||
case TOGGLE:
|
||||
activate_window(task->win);
|
||||
break;
|
||||
case ICONIFY:
|
||||
XIconifyWindow(server.display, task->win, server.screen);
|
||||
break;
|
||||
case TOGGLE_ICONIFY:
|
||||
if (active_task && task->win == active_task->win)
|
||||
XIconifyWindow(server.display, task->win, server.screen);
|
||||
else
|
||||
activate_window(task->win);
|
||||
break;
|
||||
case SHADE:
|
||||
toggle_window_shade(task->win);
|
||||
break;
|
||||
case MAXIMIZE_RESTORE:
|
||||
toggle_window_maximized(task->win);
|
||||
break;
|
||||
case MAXIMIZE:
|
||||
toggle_window_maximized(task->win);
|
||||
break;
|
||||
case RESTORE:
|
||||
toggle_window_maximized(task->win);
|
||||
break;
|
||||
case DESKTOP_LEFT: {
|
||||
if (task->desktop == 0)
|
||||
break;
|
||||
int desktop = task->desktop - 1;
|
||||
change_window_desktop(task->win, desktop);
|
||||
if (desktop == server.desktop)
|
||||
activate_window(task->win);
|
||||
break;
|
||||
}
|
||||
case DESKTOP_RIGHT: {
|
||||
if (task->desktop == server.num_desktops)
|
||||
break;
|
||||
int desktop = task->desktop + 1;
|
||||
change_window_desktop(task->win, desktop);
|
||||
if (desktop == server.desktop)
|
||||
activate_window(task->win);
|
||||
break;
|
||||
}
|
||||
case NEXT_TASK: {
|
||||
Task *task1 = next_task(find_active_task(task));
|
||||
activate_window(task1->win);
|
||||
} break;
|
||||
case PREV_TASK: {
|
||||
Task *task1 = prev_task(find_active_task(task));
|
||||
activate_window(task1->win);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void task_update_desktop(Task *task)
|
||||
{
|
||||
// fprintf(stderr, "tint2: %s %d:\n", __FUNCTION__, __LINE__);
|
||||
Window win = task->win;
|
||||
remove_task(task);
|
||||
task = add_task(win);
|
||||
reset_active_task();
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <Imlib2.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "timer.h"
|
||||
|
||||
@@ -85,9 +86,11 @@ void draw_task(void *obj, cairo_t *c);
|
||||
void on_change_task(void *obj);
|
||||
|
||||
void task_update_icon(Task *task);
|
||||
void task_update_desktop(Task *task);
|
||||
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);
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -39,6 +39,7 @@ Task *active_task;
|
||||
Task *task_drag;
|
||||
gboolean taskbar_enabled;
|
||||
gboolean taskbar_distribute_size;
|
||||
gboolean hide_task_diff_desktop;
|
||||
gboolean hide_inactive_tasks;
|
||||
gboolean hide_task_diff_monitor;
|
||||
gboolean hide_taskbar_if_empty;
|
||||
@@ -74,6 +75,7 @@ void default_taskbar()
|
||||
urgent_list = NULL;
|
||||
taskbar_enabled = FALSE;
|
||||
taskbar_distribute_size = FALSE;
|
||||
hide_task_diff_desktop = FALSE;
|
||||
hide_inactive_tasks = FALSE;
|
||||
hide_task_diff_monitor = FALSE;
|
||||
hide_taskbar_if_empty = FALSE;
|
||||
@@ -238,9 +240,9 @@ void init_taskbar_panel(void *p)
|
||||
if ((panel->g_task.config_background_mask & (1 << TASK_URGENT)) == 0)
|
||||
panel->g_task.background[TASK_URGENT] = panel->g_task.background[TASK_ACTIVE];
|
||||
|
||||
if (!panel->g_task.maximum_width)
|
||||
if (!panel->g_task.maximum_width || !panel_horizontal)
|
||||
panel->g_task.maximum_width = server.monitors[panel->monitor].width;
|
||||
if (!panel->g_task.maximum_height)
|
||||
if (!panel->g_task.maximum_height || panel_horizontal)
|
||||
panel->g_task.maximum_height = server.monitors[panel->monitor].height;
|
||||
|
||||
if (panel_horizontal) {
|
||||
@@ -265,7 +267,7 @@ 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) {
|
||||
printf("task%sbackground_id has a too large rounded value. Please fix your tint2rc\n",
|
||||
fprintf(stderr, "tint2: task%sbackground_id has a too large rounded value. Please fix your tint2rc\n",
|
||||
j == 0 ? "_" : j == 1 ? "_active_" : j == 2 ? "_iconified_" : "_urgent_");
|
||||
g_array_append_val(backgrounds, *panel->g_task.background[j]);
|
||||
panel->g_task.background[j] = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||
@@ -288,7 +290,8 @@ void init_taskbar_panel(void *p)
|
||||
FALSE);
|
||||
|
||||
panel->g_task.text_posx = left_bg_border_width(panel->g_task.background[0]) + panel->g_task.area.paddingxlr;
|
||||
panel->g_task.text_height = panel->g_task.area.height - (2 * panel->g_task.area.paddingy);
|
||||
panel->g_task.text_height =
|
||||
panel->g_task.area.height - (2 * panel->g_task.area.paddingy) - top_bottom_border_width(&panel->g_task.area);
|
||||
if (panel->g_task.has_icon) {
|
||||
panel->g_task.icon_size1 = MIN(MIN(panel->g_task.maximum_width, panel->g_task.maximum_height),
|
||||
MIN(panel->g_task.area.width, panel->g_task.area.height)) -
|
||||
@@ -296,16 +299,6 @@ void init_taskbar_panel(void *p)
|
||||
top_bottom_border_width(&panel->g_task.area));
|
||||
panel->g_task.text_posx += panel->g_task.icon_size1 + panel->g_task.area.paddingx;
|
||||
panel->g_task.icon_posy = (panel->g_task.area.height - panel->g_task.icon_size1) / 2;
|
||||
if (0)
|
||||
printf("task: icon_size = %d, textx = %f, texth = %f, icony = %d, w = %d, h = %d, maxw = %d, maxh = %d\n",
|
||||
panel->g_task.icon_size1,
|
||||
panel->g_task.text_posx,
|
||||
panel->g_task.text_height,
|
||||
panel->g_task.icon_posy,
|
||||
panel->g_task.area.width,
|
||||
panel->g_task.area.height,
|
||||
panel->g_task.maximum_width,
|
||||
panel->g_task.maximum_height);
|
||||
}
|
||||
|
||||
Taskbar *taskbar;
|
||||
@@ -392,7 +385,7 @@ void taskbar_refresh_tasklist()
|
||||
{
|
||||
if (!taskbar_enabled)
|
||||
return;
|
||||
// fprintf(stderr, "%s %d:\n", __FUNCTION__, __LINE__);
|
||||
// fprintf(stderr, "tint2: %s %d:\n", __FUNCTION__, __LINE__);
|
||||
|
||||
int num_results;
|
||||
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
||||
@@ -439,7 +432,7 @@ gboolean resize_taskbar(void *obj)
|
||||
Taskbar *taskbar = (Taskbar *)obj;
|
||||
Panel *panel = (Panel *)taskbar->area.panel;
|
||||
|
||||
// printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
|
||||
// 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);
|
||||
|
||||
@@ -534,6 +527,15 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state)
|
||||
for (; l; l = l->next)
|
||||
schedule_redraw((Area *)l->data);
|
||||
}
|
||||
if (taskbar_mode == MULTI_DESKTOP && hide_task_diff_desktop) {
|
||||
GList *l = taskbar->area.children;
|
||||
if (taskbarname_enabled)
|
||||
l = l->next;
|
||||
for (; l; l = l->next) {
|
||||
Task *task = (Task *)l->data;
|
||||
set_task_state(task, task->current_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct GlobalTaskbar {
|
||||
|
||||
extern gboolean taskbar_enabled;
|
||||
extern gboolean taskbar_distribute_size;
|
||||
extern gboolean hide_task_diff_desktop;
|
||||
extern gboolean hide_inactive_tasks;
|
||||
extern gboolean hide_task_diff_monitor;
|
||||
extern gboolean hide_taskbar_if_empty;
|
||||
|
||||
@@ -214,3 +214,35 @@ void draw_taskbarname(void *obj, cairo_t *c)
|
||||
|
||||
g_object_unref(layout);
|
||||
}
|
||||
|
||||
void update_desktop_names()
|
||||
{
|
||||
if (!taskbarname_enabled)
|
||||
return;
|
||||
GSList *list = get_desktop_names();
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
int j;
|
||||
GSList *l;
|
||||
for (j = 0, l = list; j < panels[i].num_desktops; j++) {
|
||||
gchar *name;
|
||||
if (l) {
|
||||
name = g_strdup(l->data);
|
||||
l = l->next;
|
||||
} else {
|
||||
name = g_strdup_printf("%d", j + 1);
|
||||
}
|
||||
Taskbar *taskbar = &panels[i].taskbar[j];
|
||||
if (strcmp(name, taskbar->bar_name.name) != 0) {
|
||||
g_free(taskbar->bar_name.name);
|
||||
taskbar->bar_name.name = name;
|
||||
taskbar->bar_name.area.resize_needed = 1;
|
||||
} else {
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GSList *l = list; l; l = l->next)
|
||||
g_free(l->data);
|
||||
g_slist_free(list);
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
@@ -23,4 +23,6 @@ gboolean resize_taskbarname(void *obj);
|
||||
|
||||
void taskbarname_default_font_changed();
|
||||
|
||||
void update_desktop_names();
|
||||
|
||||
#endif
|
||||
|
||||
2183
src/tint.c
2183
src/tint.c
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ include_directories( ../util
|
||||
set(SOURCES ../util/common.c
|
||||
../util/strnatcmp.c
|
||||
../util/cache.c
|
||||
../util/timer.c
|
||||
../config.c
|
||||
../server.c
|
||||
../launcher/apps-common.c
|
||||
|
||||
@@ -227,7 +227,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
gchar *tint2_config_dir = g_build_filename(g_get_user_config_dir(), "tint2", NULL);
|
||||
if (!g_file_test(tint2_config_dir, G_FILE_TEST_IS_DIR))
|
||||
g_mkdir(tint2_config_dir, 0700);
|
||||
g_mkdir_with_parents(tint2_config_dir, 0700);
|
||||
g_free(tint2_config_dir);
|
||||
}
|
||||
|
||||
|
||||
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
17
src/tint2conf/po/update-translations.sh
Executable file
17
src/tint2conf/po/update-translations.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
find .. -name '*.c' | sort -r | xargs xgettext --keyword=_ --language=C --output=tint2conf.pot -
|
||||
sed -i "s/PACKAGE VERSION/tint2conf $(../../../get_version.sh | head -n1)/g" tint2conf.pot
|
||||
sed -i "s/CHARSET/UTF-8/g" tint2conf.pot
|
||||
|
||||
for f in *.po
|
||||
do
|
||||
lang=$(basename $f .po)
|
||||
echo $lang
|
||||
msgmerge -i -o $lang.pox $lang.po tint2conf.pot
|
||||
cat ${lang}.pox > ${lang}.po
|
||||
rm ${lang}.pox
|
||||
done
|
||||
@@ -31,7 +31,7 @@ GtkWidget *panel_window_name, *disable_transparency;
|
||||
GtkWidget *panel_mouse_effects;
|
||||
GtkWidget *mouse_hover_icon_opacity, *mouse_hover_icon_saturation, *mouse_hover_icon_brightness;
|
||||
GtkWidget *mouse_pressed_icon_opacity, *mouse_pressed_icon_saturation, *mouse_pressed_icon_brightness;
|
||||
GtkWidget *panel_primary_monitor_first, *panel_shrink;
|
||||
GtkWidget *panel_shrink;
|
||||
|
||||
GtkListStore *panel_items, *all_items;
|
||||
GtkWidget *panel_items_view, *all_items_view;
|
||||
@@ -44,7 +44,7 @@ GtkWidget *notebook;
|
||||
|
||||
// taskbar
|
||||
GtkWidget *taskbar_show_desktop, *taskbar_show_name, *taskbar_padding_x, *taskbar_padding_y, *taskbar_spacing;
|
||||
GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor;
|
||||
GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor, *taskbar_hide_diff_desktop;
|
||||
GtkWidget *taskbar_name_padding_x, *taskbar_name_padding_y, *taskbar_name_inactive_color, *taskbar_name_active_color;
|
||||
GtkWidget *taskbar_name_font, *taskbar_name_font_set;
|
||||
GtkWidget *taskbar_active_background, *taskbar_inactive_background;
|
||||
@@ -80,10 +80,10 @@ GtkWidget *clock_font_line1, *clock_font_line1_set, *clock_font_line2, *clock_fo
|
||||
GtkWidget *clock_background;
|
||||
|
||||
// battery
|
||||
GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd;
|
||||
GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd, *battery_alert_full_cmd;
|
||||
GtkWidget *battery_padding_x, *battery_padding_y;
|
||||
GtkWidget *battery_font_line1, *battery_font_line1_set, *battery_font_line2, *battery_font_line2_set,
|
||||
*battery_font_color;
|
||||
*battery_font_color, *battery_format1, *battery_format2;
|
||||
GtkWidget *battery_background;
|
||||
GtkWidget *battery_tooltip;
|
||||
GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command,
|
||||
@@ -477,6 +477,7 @@ void create_panel(GtkWidget *parent)
|
||||
gtk_table_attach(GTK_TABLE(table), panel_combo_monitor, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(panel_combo_monitor), _("All"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(panel_combo_monitor), _("Primary"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(panel_combo_monitor), _("1"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(panel_combo_monitor), _("2"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(panel_combo_monitor), _("3"));
|
||||
@@ -486,24 +487,6 @@ void create_panel(GtkWidget *parent)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 0);
|
||||
gtk_tooltips_set_tip(tooltips, panel_combo_monitor, _("The monitor on which the panel is placed"), NULL);
|
||||
|
||||
row++;
|
||||
col = 2;
|
||||
label = gtk_label_new(_("Primary monitor first"));
|
||||
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++;
|
||||
|
||||
panel_primary_monitor_first = gtk_check_button_new();
|
||||
gtk_widget_show(panel_primary_monitor_first);
|
||||
gtk_table_attach(GTK_TABLE(table), panel_primary_monitor_first, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
gtk_tooltips_set_tip(tooltips,
|
||||
panel_primary_monitor_first,
|
||||
_("If enabled, the primary monitor will have index 1 in the monitor list even if it is not "
|
||||
"top-left."),
|
||||
NULL);
|
||||
|
||||
row++;
|
||||
col = 2;
|
||||
label = gtk_label_new(_("Length"));
|
||||
@@ -1856,7 +1839,7 @@ void load_desktop_file(const char *file, gboolean selected)
|
||||
if (pixbuf)
|
||||
g_object_unref(pixbuf);
|
||||
} else {
|
||||
printf("Could not load %s\n", file);
|
||||
fprintf(stderr, "tint2: Could not load %s\n", file);
|
||||
GdkPixbuf *pixbuf = load_icon(DEFAULT_ICON);
|
||||
GtkTreeIter iter;
|
||||
gtk_list_store_append(store, &iter);
|
||||
@@ -1914,7 +1897,7 @@ void load_desktop_entry(const char *file, GList **entries)
|
||||
|
||||
DesktopEntry *entry = calloc(1, sizeof(DesktopEntry));
|
||||
if (!read_desktop_file(file, entry))
|
||||
printf("Could not load %s\n", file);
|
||||
fprintf(stderr, "tint2: Could not load %s\n", file);
|
||||
if (entry->hidden_from_menus) {
|
||||
free(entry);
|
||||
return;
|
||||
@@ -2497,7 +2480,7 @@ void create_launcher(GtkWidget *parent, GtkWindow *window)
|
||||
|
||||
change_paragraph(parent);
|
||||
|
||||
fprintf(stderr, "Loading icon themes\n");
|
||||
fprintf(stderr, "tint2: Loading icon themes\n");
|
||||
GList *themes = NULL;
|
||||
const GSList *location;
|
||||
for (location = get_icon_locations(); location; location = g_slist_next(location)) {
|
||||
@@ -2526,9 +2509,9 @@ void create_launcher(GtkWidget *parent, GtkWindow *window)
|
||||
free_icon_theme((IconTheme *)l->data);
|
||||
}
|
||||
g_list_free(themes);
|
||||
fprintf(stderr, "Icon themes loaded\n");
|
||||
fprintf(stderr, "tint2: Icon themes loaded\n");
|
||||
|
||||
fprintf(stderr, "Loading .desktop files\n");
|
||||
fprintf(stderr, "tint2: Loading .desktop files\n");
|
||||
GList *entries = NULL;
|
||||
for (location = get_apps_locations(); location; location = g_slist_next(location)) {
|
||||
const gchar *path = (gchar *)location->data;
|
||||
@@ -2545,7 +2528,7 @@ void create_launcher(GtkWidget *parent, GtkWindow *window)
|
||||
icon_theme_changed(window);
|
||||
load_icons(launcher_apps);
|
||||
load_icons(all_apps);
|
||||
fprintf(stderr, "Desktop files loaded\n");
|
||||
fprintf(stderr, "tint2: Desktop files loaded\n");
|
||||
}
|
||||
|
||||
void create_taskbar(GtkWidget *parent)
|
||||
@@ -2651,6 +2634,19 @@ void create_taskbar(GtkWidget *parent)
|
||||
"This behavior is enabled automatically if the panel monitor is set to 'All'."),
|
||||
NULL);
|
||||
|
||||
col = 2;
|
||||
row++;
|
||||
label = gtk_label_new(_("Hide tasks from different desktops"));
|
||||
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++;
|
||||
|
||||
taskbar_hide_diff_desktop = gtk_check_button_new();
|
||||
gtk_widget_show(taskbar_hide_diff_desktop);
|
||||
gtk_table_attach(GTK_TABLE(table), taskbar_hide_diff_desktop, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
col = 2;
|
||||
row++;
|
||||
label = gtk_label_new(_("Always show all desktop tasks"));
|
||||
@@ -5156,6 +5152,7 @@ void create_systemtray(GtkWidget *parent)
|
||||
gtk_widget_show(systray_monitor);
|
||||
gtk_table_attach(GTK_TABLE(table), systray_monitor, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(systray_monitor), _("Primary"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(systray_monitor), _("1"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(systray_monitor), _("2"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(systray_monitor), _("3"));
|
||||
@@ -5419,6 +5416,19 @@ void create_battery(GtkWidget *parent)
|
||||
_("Command to be executed when the alert threshold is reached."),
|
||||
NULL);
|
||||
|
||||
row++, col = 2;
|
||||
label = gtk_label_new(_("Battery full command"));
|
||||
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++;
|
||||
|
||||
battery_alert_full_cmd = gtk_entry_new();
|
||||
gtk_widget_show(battery_alert_full_cmd);
|
||||
gtk_entry_set_width_chars(GTK_ENTRY(battery_alert_full_cmd), 50);
|
||||
gtk_table_attach(GTK_TABLE(table), battery_alert_full_cmd, col, col + 3, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
change_paragraph(parent);
|
||||
|
||||
label = gtk_label_new(_("<b>AC connection events</b>"));
|
||||
@@ -5736,6 +5746,46 @@ void create_battery(GtkWidget *parent)
|
||||
_("Specifies the font clor used to display the battery text."),
|
||||
NULL);
|
||||
|
||||
row++, col = 2;
|
||||
label = gtk_label_new(_("First line format"));
|
||||
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++;
|
||||
|
||||
battery_format1 = gtk_entry_new();
|
||||
gtk_widget_show(battery_format1);
|
||||
gtk_entry_set_width_chars(GTK_ENTRY(battery_format1), 16);
|
||||
gtk_table_attach(GTK_TABLE(table), battery_format1, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
char *bat_format_spec = "Format specification:\n"
|
||||
" %s: State (charging, discharging, full, unknown).\n"
|
||||
" %m: Minutes left until completely charged/discharged (estimated).\n"
|
||||
" %h: Hours left until completely charged/discharged (estimated).\n"
|
||||
" %t: Time left. Shows \"hrs:mins\" when charging/discharging, or \"Full\".\n"
|
||||
" %p: Percentage. Includes the % sign.";
|
||||
gtk_tooltips_set_tip(tooltips,
|
||||
battery_format1,
|
||||
_(bat_format_spec),
|
||||
NULL);
|
||||
|
||||
row++, col = 2;
|
||||
label = gtk_label_new(_("Second line format"));
|
||||
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++;
|
||||
|
||||
battery_format2 = gtk_entry_new();
|
||||
gtk_widget_show(battery_format2);
|
||||
gtk_entry_set_width_chars(GTK_ENTRY(battery_format2), 16);
|
||||
gtk_table_attach(GTK_TABLE(table), battery_format2, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
gtk_tooltips_set_tip(tooltips,
|
||||
battery_format2,
|
||||
_(bat_format_spec),
|
||||
NULL);
|
||||
|
||||
change_paragraph(parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ extern GtkWidget *panel_window_name, *disable_transparency;
|
||||
extern GtkWidget *panel_mouse_effects;
|
||||
extern GtkWidget *mouse_hover_icon_opacity, *mouse_hover_icon_saturation, *mouse_hover_icon_brightness;
|
||||
extern GtkWidget *mouse_pressed_icon_opacity, *mouse_pressed_icon_saturation, *mouse_pressed_icon_brightness;
|
||||
extern GtkWidget *panel_primary_monitor_first, *panel_shrink;
|
||||
extern GtkWidget *panel_shrink;
|
||||
|
||||
enum { itemsColName = 0, itemsColValue, itemsNumCols };
|
||||
extern GtkListStore *panel_items, *all_items;
|
||||
@@ -49,7 +49,7 @@ extern GtkWidget *panel_background;
|
||||
|
||||
// taskbar
|
||||
extern GtkWidget *taskbar_show_desktop, *taskbar_show_name, *taskbar_padding_x, *taskbar_padding_y, *taskbar_spacing;
|
||||
extern GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor;
|
||||
extern GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor, *taskbar_hide_diff_desktop;
|
||||
extern GtkWidget *taskbar_name_padding_x, *taskbar_name_padding_y, *taskbar_name_inactive_color,
|
||||
*taskbar_name_active_color;
|
||||
extern GtkWidget *taskbar_name_font, *taskbar_name_font_set;
|
||||
@@ -88,10 +88,10 @@ extern GtkWidget *clock_font_line1, *clock_font_line1_set, *clock_font_line2, *c
|
||||
extern GtkWidget *clock_background;
|
||||
|
||||
// battery
|
||||
extern GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd;
|
||||
extern GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd, *battery_alert_full_cmd;
|
||||
extern GtkWidget *battery_padding_x, *battery_padding_y;
|
||||
extern GtkWidget *battery_font_line1, *battery_font_line1_set, *battery_font_line2, *battery_font_line2_set,
|
||||
*battery_font_color;
|
||||
*battery_font_color, *battery_format1, *battery_format2;
|
||||
extern GtkWidget *battery_background;
|
||||
extern GtkWidget *battery_tooltip;
|
||||
extern GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command,
|
||||
|
||||
@@ -326,17 +326,15 @@ void config_write_panel(FILE *fp)
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "panel_monitor = ");
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(panel_combo_monitor)) == 0) {
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(panel_combo_monitor)) <= 0) {
|
||||
fprintf(fp, "all");
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(panel_combo_monitor)) == 1) {
|
||||
fprintf(fp, "primary");
|
||||
} else {
|
||||
fprintf(fp, "%d", gtk_combo_box_get_active(GTK_COMBO_BOX(panel_combo_monitor)));
|
||||
fprintf(fp, "%d", gtk_combo_box_get_active(GTK_COMBO_BOX(panel_combo_monitor)) - 1);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp,
|
||||
"primary_monitor_first = %d\n",
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel_primary_monitor_first)) ? 1 : 0);
|
||||
|
||||
fprintf(fp, "panel_shrink = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel_shrink)) ? 1 : 0);
|
||||
|
||||
fprintf(fp, "autohide = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel_autohide)) ? 1 : 0);
|
||||
@@ -401,6 +399,9 @@ void config_write_taskbar(FILE *fp)
|
||||
fprintf(fp,
|
||||
"taskbar_hide_different_monitor = %d\n",
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(taskbar_hide_diff_monitor)) ? 1 : 0);
|
||||
fprintf(fp,
|
||||
"taskbar_hide_different_desktop = %d\n",
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(taskbar_hide_diff_desktop)) ? 1 : 0);
|
||||
fprintf(fp,
|
||||
"taskbar_always_show_all_desktop_tasks = %d\n",
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(taskbar_always_show_all_desktop_tasks)) ? 1 : 0);
|
||||
@@ -629,7 +630,11 @@ void config_write_systray(FILE *fp)
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(systray_icon_brightness)));
|
||||
|
||||
fprintf(fp, "systray_monitor = ");
|
||||
fprintf(fp, "%d", MAX(1, 1 + gtk_combo_box_get_active(GTK_COMBO_BOX(systray_monitor))));
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(systray_monitor)) <= 0) {
|
||||
fprintf(fp, "primary");
|
||||
} else {
|
||||
fprintf(fp, "%d", MAX(1, gtk_combo_box_get_active(GTK_COMBO_BOX(systray_monitor))));
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "systray_name_filter = %s\n", gtk_entry_get_text(GTK_ENTRY(systray_name_filter)));
|
||||
@@ -752,6 +757,7 @@ void config_write_battery(FILE *fp)
|
||||
fprintf(fp, "battery_tooltip = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(battery_tooltip)) ? 1 : 0);
|
||||
fprintf(fp, "battery_low_status = %g\n", gtk_spin_button_get_value(GTK_SPIN_BUTTON(battery_alert_if_lower)));
|
||||
fprintf(fp, "battery_low_cmd = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_alert_cmd)));
|
||||
fprintf(fp, "battery_full_cmd = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_alert_full_cmd)));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(battery_font_line1_set)))
|
||||
fprintf(fp, "bat1_font = %s\n", gtk_font_button_get_font_name(GTK_FONT_BUTTON(battery_font_line1)));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(battery_font_line2_set)))
|
||||
@@ -762,6 +768,8 @@ void config_write_battery(FILE *fp)
|
||||
"battery_font_color",
|
||||
color,
|
||||
gtk_color_button_get_alpha(GTK_COLOR_BUTTON(battery_font_color)) * 100 / 0xffff);
|
||||
fprintf(fp, "bat1_format = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_format1)));
|
||||
fprintf(fp, "bat2_format = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_format2)));
|
||||
fprintf(fp,
|
||||
"battery_padding = %d %d\n",
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(battery_padding_x)),
|
||||
@@ -973,7 +981,7 @@ unsigned short checksum_txt(FILE *f)
|
||||
|
||||
void config_save_file(const char *path)
|
||||
{
|
||||
printf("config_save_file : %s\n", path);
|
||||
fprintf(stderr, "tint2: config_save_file : %s\n", path);
|
||||
|
||||
FILE *fp;
|
||||
if ((fp = fopen(path, "w+t")) == NULL)
|
||||
@@ -1351,20 +1359,20 @@ void add_entry(char *key, char *value)
|
||||
} else if (strcmp(key, "panel_monitor") == 0) {
|
||||
if (strcmp(value, "all") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 0);
|
||||
else if (strcmp(value, "1") == 0)
|
||||
else if (strcmp(value, "primary") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 1);
|
||||
else if (strcmp(value, "2") == 0)
|
||||
else if (strcmp(value, "1") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 2);
|
||||
else if (strcmp(value, "3") == 0)
|
||||
else if (strcmp(value, "2") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 3);
|
||||
else if (strcmp(value, "4") == 0)
|
||||
else if (strcmp(value, "3") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 4);
|
||||
else if (strcmp(value, "5") == 0)
|
||||
else if (strcmp(value, "4") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 5);
|
||||
else if (strcmp(value, "6") == 0)
|
||||
else if (strcmp(value, "5") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 6);
|
||||
} else if (strcmp(key, "primary_monitor_first") == 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel_primary_monitor_first), atoi(value));
|
||||
else if (strcmp(value, "6") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(panel_combo_monitor), 7);
|
||||
} else if (strcmp(key, "panel_shrink") == 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel_shrink), atoi(value));
|
||||
}
|
||||
@@ -1403,12 +1411,18 @@ void add_entry(char *key, char *value)
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(battery_alert_if_lower), atof(value));
|
||||
} else if (strcmp(key, "battery_low_cmd") == 0) {
|
||||
gtk_entry_set_text(GTK_ENTRY(battery_alert_cmd), value);
|
||||
} else if (strcmp(key, "battery_full_cmd") == 0) {
|
||||
gtk_entry_set_text(GTK_ENTRY(battery_alert_full_cmd), value);
|
||||
} else if (strcmp(key, "bat1_font") == 0) {
|
||||
gtk_font_button_set_font_name(GTK_FONT_BUTTON(battery_font_line1), value);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(battery_font_line1_set), TRUE);
|
||||
} else if (strcmp(key, "bat2_font") == 0) {
|
||||
gtk_font_button_set_font_name(GTK_FONT_BUTTON(battery_font_line2), value);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(battery_font_line2_set), TRUE);
|
||||
} else if (strcmp(key, "bat1_format") == 0) {
|
||||
gtk_entry_set_text(GTK_ENTRY(battery_format1), value);
|
||||
} else if (strcmp(key, "bat2_format") == 0) {
|
||||
gtk_entry_set_text(GTK_ENTRY(battery_format2), value);
|
||||
} else if (strcmp(key, "battery_font_color") == 0) {
|
||||
extract_values(value, &value1, &value2, &value3);
|
||||
GdkColor col;
|
||||
@@ -1551,6 +1565,8 @@ void add_entry(char *key, char *value)
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(taskbar_hide_inactive_tasks), atoi(value));
|
||||
} else if (strcmp(key, "taskbar_hide_different_monitor") == 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(taskbar_hide_diff_monitor), atoi(value));
|
||||
} else if (strcmp(key, "taskbar_hide_different_desktop") == 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(taskbar_hide_diff_desktop), atoi(value));
|
||||
} else if (strcmp(key, "taskbar_always_show_all_desktop_tasks") == 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(taskbar_always_show_all_desktop_tasks), atoi(value));
|
||||
} else if (strcmp(key, "taskbar_name_padding") == 0) {
|
||||
@@ -1747,18 +1763,20 @@ void add_entry(char *key, char *value)
|
||||
} else if (strcmp(key, "systray_icon_size") == 0) {
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(systray_icon_size), atoi(value));
|
||||
} else if (strcmp(key, "systray_monitor") == 0) {
|
||||
if (strcmp(value, "1") == 0)
|
||||
if (strcmp(value, "primary") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 0);
|
||||
else if (strcmp(value, "2") == 0)
|
||||
else if (strcmp(value, "1") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 1);
|
||||
else if (strcmp(value, "3") == 0)
|
||||
else if (strcmp(value, "2") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 2);
|
||||
else if (strcmp(value, "4") == 0)
|
||||
else if (strcmp(value, "3") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 3);
|
||||
else if (strcmp(value, "5") == 0)
|
||||
else if (strcmp(value, "4") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 4);
|
||||
else if (strcmp(value, "6") == 0)
|
||||
else if (strcmp(value, "5") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 5);
|
||||
else if (strcmp(value, "6") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(systray_monitor), 6);
|
||||
} else if (strcmp(key, "systray_icon_asb") == 0) {
|
||||
extract_values(value, &value1, &value2, &value3);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(systray_icon_opacity), atoi(value1));
|
||||
|
||||
@@ -145,10 +145,16 @@ void theme_list_append(const gchar *path)
|
||||
GtkTreeIter iter;
|
||||
gtk_list_store_append(theme_list_store, &iter);
|
||||
|
||||
gchar *name = strrchr(path, '/') + 1;
|
||||
gchar *name, *dir;
|
||||
|
||||
gchar *dir = g_strdup(path);
|
||||
strrchr(dir, '/')[0] = 0;
|
||||
if (strchr(path, '/')) {
|
||||
name = strrchr(path, '/') + 1;
|
||||
dir = g_strdup(path);
|
||||
strrchr(dir, '/')[0] = 0;
|
||||
} else {
|
||||
name = (gchar*)path;
|
||||
dir = g_strdup(".");
|
||||
}
|
||||
char *suffix = contract_tilde(dir);
|
||||
g_free(dir);
|
||||
|
||||
@@ -171,7 +177,7 @@ gboolean update_snapshot(gpointer ignored)
|
||||
{
|
||||
gchar *tint2_cache_dir = g_build_filename(g_get_user_cache_dir(), "tint2", NULL);
|
||||
if (!g_file_test(tint2_cache_dir, G_FILE_TEST_IS_DIR))
|
||||
g_mkdir(tint2_cache_dir, 0700);
|
||||
g_mkdir_with_parents(tint2_cache_dir, 0700);
|
||||
g_free(tint2_cache_dir);
|
||||
}
|
||||
|
||||
|
||||
164
src/tracing.c
Normal file
164
src/tracing.c
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "timer.h"
|
||||
|
||||
#ifdef HAVE_TRACING
|
||||
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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"
|
||||
|
||||
static GList *tracing_events = NULL;
|
||||
static sig_atomic_t tracing = FALSE;
|
||||
|
||||
typedef struct TracingEvent {
|
||||
void *address;
|
||||
void *caller;
|
||||
double time;
|
||||
gboolean enter;
|
||||
} TracingEvent;
|
||||
|
||||
void __attribute__ ((constructor)) init_tracing()
|
||||
{
|
||||
tracing_events = NULL;
|
||||
tracing = FALSE;
|
||||
}
|
||||
|
||||
void cleanup_tracing()
|
||||
{
|
||||
g_list_free_full(tracing_events, free);
|
||||
tracing_events = NULL;
|
||||
tracing = FALSE;
|
||||
}
|
||||
|
||||
char *addr2name(void *func)
|
||||
{
|
||||
#ifdef ENABLE_EXECINFO
|
||||
void *array[1];
|
||||
array[0] = func;
|
||||
char **strings = backtrace_symbols(array, 1);
|
||||
char *result = strdup(strings[0] ? strings[0] : "??");
|
||||
free(strings);
|
||||
return result;
|
||||
#else
|
||||
char *result = (char*) calloc(32, 1);
|
||||
sprintf(result, "%p", func);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void add_tracing_event(void *func, void *caller, gboolean enter)
|
||||
{
|
||||
TracingEvent *entry = (TracingEvent *)calloc(sizeof(TracingEvent), 1);
|
||||
entry->address = func;
|
||||
entry->caller = caller;
|
||||
entry->time = get_time();
|
||||
entry->enter = enter;
|
||||
tracing_events = g_list_append(tracing_events, entry);
|
||||
}
|
||||
|
||||
void start_tracing(void *root)
|
||||
{
|
||||
if (tracing_events)
|
||||
cleanup_tracing();
|
||||
add_tracing_event(root, NULL, TRUE);
|
||||
tracing = TRUE;
|
||||
}
|
||||
|
||||
void stop_tracing()
|
||||
{
|
||||
tracing = FALSE;
|
||||
}
|
||||
|
||||
void __cyg_profile_func_enter(void *func, void *caller)
|
||||
{
|
||||
if (tracing)
|
||||
add_tracing_event(func, caller, TRUE);
|
||||
}
|
||||
|
||||
void __cyg_profile_func_exit(void *func, void *caller)
|
||||
{
|
||||
if (tracing)
|
||||
add_tracing_event(func, caller, FALSE);
|
||||
}
|
||||
|
||||
void print_tracing_events()
|
||||
{
|
||||
GList *stack = NULL;
|
||||
int depth = 0;
|
||||
double now = get_time();
|
||||
for (GList *i = tracing_events; i; i = i->next) {
|
||||
TracingEvent *e = (TracingEvent *)i->data;
|
||||
if (e->enter) {
|
||||
// Push a new function on the stack
|
||||
for (int d = 0; d < depth; d++)
|
||||
fprintf(stderr, "tint2: ");
|
||||
char *name = addr2name(e->address);
|
||||
char *caller = addr2name(e->caller);
|
||||
fprintf(stderr,
|
||||
"%s called from %s\n",
|
||||
name,
|
||||
caller);
|
||||
stack = g_list_append(stack, e);
|
||||
depth++;
|
||||
} else {
|
||||
// Pop a function from the stack, if matching, and print
|
||||
if (stack) {
|
||||
TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
|
||||
if (old->address == e->address) {
|
||||
depth--;
|
||||
for (int d = 0; d < depth; d++)
|
||||
fprintf(stderr, "tint2: ");
|
||||
char *name = addr2name(e->address);
|
||||
double duration = (e->time - old->time) * 1.0e3;
|
||||
fprintf(stderr,
|
||||
"-- %s exited after %.1f ms",
|
||||
name,
|
||||
duration);
|
||||
if (duration >= 1.0) {
|
||||
fprintf(stderr, YELLOW "tint2: ");
|
||||
for (int d = 0; d < duration; d++) {
|
||||
fprintf(stderr, "tint2: #");
|
||||
}
|
||||
fprintf(stderr, RESET);
|
||||
}
|
||||
fprintf(stderr, "tint2: \n");
|
||||
free(name);
|
||||
stack = g_list_delete_link(stack, g_list_last(stack));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (stack) {
|
||||
TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
|
||||
depth--;
|
||||
for (int d = 0; d < depth; d++)
|
||||
fprintf(stderr, "tint2: ");
|
||||
char *name = addr2name(old->address);
|
||||
double duration = (now - old->time) * 1.0e3;
|
||||
fprintf(stderr,
|
||||
"-- %s exited after %.1f ms",
|
||||
name,
|
||||
duration);
|
||||
if (duration >= 1.0) {
|
||||
fprintf(stderr, YELLOW "tint2: ");
|
||||
for (int d = 0; d < duration; d++) {
|
||||
fprintf(stderr, "tint2: #");
|
||||
}
|
||||
fprintf(stderr, RESET);
|
||||
}
|
||||
fprintf(stderr, "tint2: \n");
|
||||
free(name);
|
||||
stack = g_list_delete_link(stack, g_list_last(stack));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
15
src/tracing.h
Normal file
15
src/tracing.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef TRACING_H
|
||||
#define TRACING_H
|
||||
|
||||
#ifdef HAVE_TRACING
|
||||
|
||||
void init_tracing();
|
||||
void cleanup_tracing();
|
||||
|
||||
void start_tracing(void *root);
|
||||
void stop_tracing();
|
||||
void print_tracing_events();
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
195
src/util/area.c
195
src/util/area.c
@@ -224,7 +224,7 @@ int compute_desired_size(Area *a)
|
||||
if (a->_compute_desired_size)
|
||||
return a->_compute_desired_size(a);
|
||||
if (a->size_mode == LAYOUT_FIXED)
|
||||
fprintf(stderr, YELLOW "Area %s does not set desired size!" RESET "\n", a->name);
|
||||
fprintf(stderr, YELLOW "tint2: Area %s does not set desired size!" RESET "\n", a->name);
|
||||
return container_compute_desired_size(a);
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ void draw_tree(Area *a)
|
||||
a->posx,
|
||||
a->posy);
|
||||
else
|
||||
fprintf(stderr, RED "%s %d: area %s has no pixmap!!!" RESET "\n", __FILE__, __LINE__, a->name);
|
||||
fprintf(stderr, RED "tint2: %s %d: area %s has no pixmap!!!" RESET "\n", __FILE__, __LINE__, a->name);
|
||||
|
||||
for (GList *l = a->children; l; l = l->next)
|
||||
draw_tree((Area *)l->data);
|
||||
@@ -630,7 +630,7 @@ void free_area(Area *a)
|
||||
free_area_gradient_instances(a);
|
||||
}
|
||||
|
||||
void mouse_over(Area *area, int pressed)
|
||||
void mouse_over(Area *area, gboolean pressed)
|
||||
{
|
||||
if (mouse_over_area == area && !area)
|
||||
return;
|
||||
@@ -843,10 +843,10 @@ int top_bottom_bg_border_width(Background *bg)
|
||||
|
||||
void area_dump_geometry(Area *area, int indent)
|
||||
{
|
||||
fprintf(stderr, "%*s%s:\n", indent, "", area->name);
|
||||
fprintf(stderr, "tint2: %*s%s:\n", indent, "", area->name);
|
||||
indent += 2;
|
||||
if (!area->on_screen) {
|
||||
fprintf(stderr, "%*shidden\n", indent, "");
|
||||
fprintf(stderr, "tint2: %*shidden\n", indent, "");
|
||||
return;
|
||||
}
|
||||
fprintf(stderr,
|
||||
@@ -876,13 +876,190 @@ void area_dump_geometry(Area *area, int indent)
|
||||
if (area->_dump_geometry)
|
||||
area->_dump_geometry(area, indent);
|
||||
if (area->children) {
|
||||
fprintf(stderr, "%*sChildren:\n", indent, "");
|
||||
fprintf(stderr, "tint2: %*sChildren:\n", indent, "");
|
||||
indent += 2;
|
||||
for (GList *l = area->children; l; l = l->next)
|
||||
area_dump_geometry((Area *)l->data, indent);
|
||||
}
|
||||
}
|
||||
|
||||
void area_compute_text_geometry(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_height_ink,
|
||||
int *line1_height,
|
||||
int *line1_width,
|
||||
int *line2_height_ink,
|
||||
int *line2_height,
|
||||
int *line2_width)
|
||||
{
|
||||
Panel *panel = (Panel *)area->panel;
|
||||
int available_w, available_h;
|
||||
if (panel_horizontal) {
|
||||
available_w = panel->area.width;
|
||||
available_h = area->height - 2 * area->paddingy - left_right_border_width(area);
|
||||
} else {
|
||||
available_w = area->width - 2 * area->paddingxlr - left_right_border_width(area);
|
||||
available_h = panel->area.height;
|
||||
}
|
||||
|
||||
if (line1 && line1[0])
|
||||
get_text_size2(line1_font_desc,
|
||||
line1_height_ink,
|
||||
line1_height,
|
||||
line1_width,
|
||||
available_h,
|
||||
available_w,
|
||||
line1,
|
||||
strlen(line1),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
else
|
||||
*line1_width = *line1_height_ink = *line1_height = 0;
|
||||
|
||||
if (line2 && line2[0])
|
||||
get_text_size2(line2_font_desc,
|
||||
line2_height_ink,
|
||||
line2_height,
|
||||
line2_width,
|
||||
available_h,
|
||||
available_w,
|
||||
line2,
|
||||
strlen(line2),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
else
|
||||
*line2_width = *line2_height_ink = *line2_height = 0;
|
||||
}
|
||||
|
||||
int text_area_compute_desired_size(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc)
|
||||
{
|
||||
int line1_height_ink, line1_height, line1_width, line2_height_ink, line2_height, line2_width;
|
||||
area_compute_text_geometry(area,
|
||||
line1,
|
||||
line2,
|
||||
line1_font_desc,
|
||||
line2_font_desc,
|
||||
&line1_height_ink,
|
||||
&line1_height,
|
||||
&line1_width,
|
||||
&line2_height_ink,
|
||||
&line2_height,
|
||||
&line2_width);
|
||||
|
||||
if (panel_horizontal) {
|
||||
int new_size = MAX(line1_width, line2_width) + 2 * area->paddingxlr + left_right_border_width(area);
|
||||
return new_size;
|
||||
} else {
|
||||
int new_size = line1_height + line2_height + 2 * area->paddingxlr + top_bottom_border_width(area);
|
||||
return new_size;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean resize_text_area(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_posy,
|
||||
int *line2_posy)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
|
||||
schedule_redraw(area);
|
||||
|
||||
int line1_height_ink, line1_height, line1_width;
|
||||
int line2_height_ink, line2_height, line2_width;
|
||||
area_compute_text_geometry(area,
|
||||
line1,
|
||||
line2,
|
||||
line1_font_desc,
|
||||
line2_font_desc,
|
||||
&line1_height_ink,
|
||||
&line1_height,
|
||||
&line1_width,
|
||||
&line2_height_ink,
|
||||
&line2_height,
|
||||
&line2_width);
|
||||
|
||||
int new_size = text_area_compute_desired_size(area,
|
||||
line1,
|
||||
line2,
|
||||
line1_font_desc,
|
||||
line2_font_desc);
|
||||
if (panel_horizontal) {
|
||||
if (new_size != area->width) {
|
||||
if (new_size < area->width && abs(new_size - area->width) < 6) {
|
||||
// we try to limit the number of resizes
|
||||
new_size = area->width;
|
||||
} else {
|
||||
area->width = new_size;
|
||||
}
|
||||
*line1_posy = (area->height - line1_height) / 2;
|
||||
if (line2) {
|
||||
*line1_posy -= (line2_height) / 2;
|
||||
*line2_posy = *line1_posy + line1_height;
|
||||
}
|
||||
result = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (new_size != area->height) {
|
||||
area->height = new_size;
|
||||
*line1_posy = (area->height - line1_height) / 2;
|
||||
if (line2) {
|
||||
*line1_posy -= (line2_height) / 2;
|
||||
*line2_posy = *line1_posy + line1_height;
|
||||
}
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void draw_text_area(Area *area,
|
||||
cairo_t *c,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int line1_posy,
|
||||
int line2_posy,
|
||||
Color *color)
|
||||
{
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_width(layout, area->width * PANGO_SCALE);
|
||||
cairo_set_source_rgba(c, color->rgb[0], color->rgb[1], color->rgb[2], color->alpha);
|
||||
|
||||
if (line1 && line1[0]) {
|
||||
pango_layout_set_font_description(layout, line1_font_desc);
|
||||
pango_layout_set_text(layout, line1, strlen(line1));
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, line1_posy, color, ((Panel *)area->panel)->font_shadow);
|
||||
}
|
||||
|
||||
if (line2 && line2[0]) {
|
||||
pango_layout_set_font_description(layout, line2_font_desc);
|
||||
pango_layout_set_indent(layout, 0);
|
||||
pango_layout_set_text(layout, line2, strlen(line2));
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, line2_posy, color, ((Panel *)area->panel)->font_shadow);
|
||||
}
|
||||
|
||||
g_object_unref(layout);
|
||||
}
|
||||
|
||||
Area *compute_element_area(Area *area, Element element)
|
||||
{
|
||||
if (element == ELEMENT_SELF)
|
||||
@@ -955,7 +1132,7 @@ void free_gradient_instance(GradientInstance *gi)
|
||||
void instantiate_area_gradients(Area *area)
|
||||
{
|
||||
if (debug_gradients)
|
||||
fprintf(stderr, "Initializing gradients for area %s\n", area->name);
|
||||
fprintf(stderr, "tint2: Initializing gradients for area %s\n", area->name);
|
||||
for (int i = 0; i < MOUSE_STATE_COUNT; i++) {
|
||||
g_assert_null(area->gradient_instances_by_state[i]);
|
||||
GradientClass *g = area->bg->gradients[i];
|
||||
@@ -970,7 +1147,7 @@ void instantiate_area_gradients(Area *area)
|
||||
void free_area_gradient_instances(Area *area)
|
||||
{
|
||||
if (debug_gradients)
|
||||
fprintf(stderr, "Freeing gradients for area %s\n", area->name);
|
||||
fprintf(stderr, "tint2: Freeing gradients for area %s\n", area->name);
|
||||
for (int i = 0; i < MOUSE_STATE_COUNT; i++) {
|
||||
for (GList *l = area->gradient_instances_by_state[i]; l; l = l->next) {
|
||||
GradientInstance *gi = (GradientInstance *)l->data;
|
||||
@@ -996,7 +1173,7 @@ double compute_control_point_offset(Area *area, Offset *offset)
|
||||
double height = element_area->height;
|
||||
double radius = sqrt(element_area->width * element_area->width + element_area->height * element_area->height) / 2.0;
|
||||
|
||||
double left, top;
|
||||
double left = 0, top = 0;
|
||||
if (offset->element == ELEMENT_SELF) {
|
||||
left = 0;
|
||||
top = 0;
|
||||
|
||||
@@ -263,6 +263,39 @@ int relayout_with_constraint(Area *a, int maximum_size);
|
||||
int compute_desired_size(Area *a);
|
||||
int container_compute_desired_size(Area *a);
|
||||
|
||||
void area_compute_text_geometry(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_height_ink,
|
||||
int *line1_height,
|
||||
int *line1_width,
|
||||
int *line2_height_ink,
|
||||
int *line2_height,
|
||||
int *line2_width);
|
||||
int text_area_compute_desired_size(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc);
|
||||
gboolean resize_text_area(Area *area,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_posy,
|
||||
int *line2_posy);
|
||||
void draw_text_area(Area *area,
|
||||
cairo_t *c,
|
||||
const char *line1,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int line1_posy,
|
||||
int line2_posy,
|
||||
Color *color);
|
||||
|
||||
int left_border_width(Area *a);
|
||||
int right_border_width(Area *a);
|
||||
int left_right_border_width(Area *a);
|
||||
@@ -324,7 +357,7 @@ void free_area_gradient_instances(Area *area);
|
||||
|
||||
void area_dump_geometry(Area *area, int indent);
|
||||
|
||||
void mouse_over(Area *area, int pressed);
|
||||
void mouse_over(Area *area, gboolean pressed);
|
||||
void mouse_out();
|
||||
|
||||
void update_gradient(GradientInstance *gi);
|
||||
|
||||
@@ -117,14 +117,14 @@ void save_cache(Cache *cache, const gchar *cache_path)
|
||||
fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
|
||||
}
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
|
||||
fprintf(stderr, RED "tint2: Could not save icon theme cache!" RESET "\n");
|
||||
return;
|
||||
}
|
||||
flock(fd, LOCK_EX);
|
||||
|
||||
FILE *f = fopen(cache_path, "w");
|
||||
if (!f) {
|
||||
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
|
||||
fprintf(stderr, RED "tint2: Could not save icon theme cache!" RESET "\n");
|
||||
goto unlock;
|
||||
}
|
||||
g_hash_table_foreach(cache->_table, write_cache_line, f);
|
||||
|
||||
@@ -34,17 +34,176 @@
|
||||
#include "../server.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#if !defined(__OpenBSD__)
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RSVG
|
||||
#include <librsvg/rsvg.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../panel.h"
|
||||
#include "timer.h"
|
||||
|
||||
void write_string(int fd, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
while (len > 0) {
|
||||
int count = write(fd, s, len);
|
||||
if (count >= 0) {
|
||||
s += count;
|
||||
len -= count;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_string(int fd, const char *s)
|
||||
{
|
||||
write_string(2, s);
|
||||
write_string(fd, s);
|
||||
}
|
||||
|
||||
void dump_backtrace(int log_fd)
|
||||
{
|
||||
#ifndef DISABLE_BACKTRACE
|
||||
log_string(log_fd, "\n" YELLOW "Backtrace:" RESET "\n");
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
while (unw_step(&cursor) > 0) {
|
||||
unw_word_t offset;
|
||||
char fname[128];
|
||||
fname[0] = '\0';
|
||||
(void)unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
|
||||
log_string(log_fd, fname);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#define MAX_TRACE_SIZE 128
|
||||
void *array[MAX_TRACE_SIZE];
|
||||
size_t size = backtrace(array, MAX_TRACE_SIZE);
|
||||
char **strings = backtrace_symbols(array, size);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
log_string(log_fd, strings[i]);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
|
||||
free(strings);
|
||||
#endif // ENABLE_EXECINFO
|
||||
#endif // ENABLE_LIBUNWIND
|
||||
#endif // DISABLE_BACKTRACE
|
||||
}
|
||||
|
||||
// sleep() returns early when signals arrive. This function does not.
|
||||
void safe_sleep(int seconds)
|
||||
{
|
||||
double t0 = get_time();
|
||||
while (1) {
|
||||
double t = get_time();
|
||||
if (t > t0 + seconds)
|
||||
return;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
const char *signal_name(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
return "SIGHUP: Hangup (POSIX).";
|
||||
case SIGINT:
|
||||
return "SIGINT: Interrupt (ANSI).";
|
||||
case SIGQUIT:
|
||||
return "SIGQUIT: Quit (POSIX).";
|
||||
case SIGILL:
|
||||
return "SIGILL: Illegal instruction (ANSI).";
|
||||
case SIGTRAP:
|
||||
return "SIGTRAP: Trace trap (POSIX).";
|
||||
case SIGABRT:
|
||||
return "SIGABRT/SIGIOT: Abort (ANSI) / IOT trap (4.2 BSD).";
|
||||
case SIGBUS:
|
||||
return "SIGBUS: BUS error (4.2 BSD).";
|
||||
case SIGFPE:
|
||||
return "SIGFPE: Floating-point exception (ANSI).";
|
||||
case SIGKILL:
|
||||
return "SIGKILL: Kill, unblockable (POSIX).";
|
||||
case SIGUSR1:
|
||||
return "SIGUSR1: User-defined signal 1 (POSIX).";
|
||||
case SIGSEGV:
|
||||
return "SIGSEGV: Segmentation violation (ANSI).";
|
||||
case SIGUSR2:
|
||||
return "SIGUSR2: User-defined signal 2 (POSIX).";
|
||||
case SIGPIPE:
|
||||
return "SIGPIPE: Broken pipe (POSIX).";
|
||||
case SIGALRM:
|
||||
return "SIGALRM: Alarm clock (POSIX).";
|
||||
case SIGTERM:
|
||||
return "SIGTERM: Termination (ANSI).";
|
||||
// case SIGSTKFLT: return "SIGSTKFLT: Stack fault.";
|
||||
case SIGCHLD:
|
||||
return "SIGCHLD: Child status has changed (POSIX).";
|
||||
case SIGCONT:
|
||||
return "SIGCONT: Continue (POSIX).";
|
||||
case SIGSTOP:
|
||||
return "SIGSTOP: Stop, unblockable (POSIX).";
|
||||
case SIGTSTP:
|
||||
return "SIGTSTP: Keyboard stop (POSIX).";
|
||||
case SIGTTIN:
|
||||
return "SIGTTIN: Background read from tty (POSIX).";
|
||||
case SIGTTOU:
|
||||
return "SIGTTOU: Background write to tty (POSIX).";
|
||||
case SIGURG:
|
||||
return "SIGURG: Urgent condition on socket (4.2 BSD).";
|
||||
case SIGXCPU:
|
||||
return "SIGXCPU: CPU limit exceeded (4.2 BSD).";
|
||||
case SIGXFSZ:
|
||||
return "SIGXFSZ: File size limit exceeded (4.2 BSD).";
|
||||
case SIGVTALRM:
|
||||
return "SIGVTALRM: Virtual alarm clock (4.2 BSD).";
|
||||
case SIGPROF:
|
||||
return "SIGPROF: Profiling alarm clock (4.2 BSD).";
|
||||
// case SIGPWR: return "SIGPWR: Power failure restart (System V).";
|
||||
case SIGSYS:
|
||||
return "SIGSYS: Bad system call.";
|
||||
}
|
||||
static char s[64];
|
||||
sprintf(s, "SIG=%d: Unknown", sig);
|
||||
return s;
|
||||
}
|
||||
|
||||
const char *get_home_dir()
|
||||
{
|
||||
const char *s = getenv("HOME");
|
||||
if (s)
|
||||
return s;
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (!pw)
|
||||
return NULL;
|
||||
return pw->pw_dir;
|
||||
}
|
||||
|
||||
void copy_file(const char *path_src, const char *path_dest)
|
||||
{
|
||||
@@ -67,7 +226,7 @@ void copy_file(const char *path_src, const char *path_dest)
|
||||
|
||||
while ((nb = fread(buffer, 1, sizeof(buffer), file_src)) > 0) {
|
||||
if (nb != fwrite(buffer, 1, nb, file_dest)) {
|
||||
printf("Error while copying file %s to %s\n", path_src, path_dest);
|
||||
fprintf(stderr, "tint2: Error while copying file %s to %s\n", path_src, path_dest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,24 +262,118 @@ gboolean parse_line(const char *line, char **key, char **value)
|
||||
|
||||
extern char *config_path;
|
||||
|
||||
void tint_exec(const char *command, const char *dir, const char *tooltip, Time time)
|
||||
int setenvd(const char *name, const int value)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf(buf, "%d", value);
|
||||
return setenv(name, buf, 1);
|
||||
}
|
||||
|
||||
#ifndef TINT2CONF
|
||||
pid_t tint_exec(const char *command,
|
||||
const char *dir,
|
||||
const char *tooltip,
|
||||
Time time,
|
||||
Area *area,
|
||||
int x,
|
||||
int y,
|
||||
gboolean terminal,
|
||||
gboolean startup_notification)
|
||||
{
|
||||
if (!command || strlen(command) == 0)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (area) {
|
||||
Panel *panel = (Panel *)area->panel;
|
||||
|
||||
int aligned_x, aligned_y, aligned_x1, aligned_y1, aligned_x2, aligned_y2;
|
||||
int panel_x1, panel_x2, panel_y1, panel_y2;
|
||||
if (panel_horizontal) {
|
||||
if (area_is_first(area))
|
||||
aligned_x1 = panel->posx;
|
||||
else
|
||||
aligned_x1 = panel->posx + area->posx;
|
||||
|
||||
if (area_is_last(area))
|
||||
aligned_x2 = panel->posx + panel->area.width;
|
||||
else
|
||||
aligned_x2 = panel->posx + area->posx + area->width;
|
||||
|
||||
if (area_is_first(area))
|
||||
aligned_x = aligned_x1;
|
||||
else if (area_is_last(area))
|
||||
aligned_x = aligned_x2;
|
||||
else
|
||||
aligned_x = aligned_x1;
|
||||
|
||||
if (panel_position & BOTTOM)
|
||||
aligned_y = panel->posy;
|
||||
else
|
||||
aligned_y = panel->posy + panel->area.height;
|
||||
|
||||
aligned_y1 = aligned_y2 = aligned_y;
|
||||
|
||||
panel_x1 = panel->posx;
|
||||
panel_x2 = panel->posx + panel->area.width;
|
||||
panel_y1 = panel_y2 = aligned_y;
|
||||
} else {
|
||||
if (area_is_first(area))
|
||||
aligned_y1 = panel->posy;
|
||||
else
|
||||
aligned_y1 = panel->posy + area->posy;
|
||||
|
||||
if (area_is_last(area))
|
||||
aligned_y2 = panel->posy + panel->area.height;
|
||||
else
|
||||
aligned_y2 = panel->posy + area->posy + area->height;
|
||||
|
||||
if (area_is_first(area))
|
||||
aligned_y = aligned_y1;
|
||||
else if (area_is_last(area))
|
||||
aligned_y = aligned_y2;
|
||||
else
|
||||
aligned_y = aligned_y1;
|
||||
|
||||
if (panel_position & RIGHT)
|
||||
aligned_x = panel->posx;
|
||||
else
|
||||
aligned_x = panel->posx + panel->area.width;
|
||||
|
||||
aligned_x1 = aligned_x2 = aligned_x;
|
||||
|
||||
panel_x1 = panel_x2 = aligned_x;
|
||||
panel_y1 = panel->posy;
|
||||
panel_y2 = panel->posy + panel->area.height;
|
||||
}
|
||||
|
||||
setenv("TINT2_CONFIG", config_path, 1);
|
||||
setenvd("TINT2_BUTTON_X", x);
|
||||
setenvd("TINT2_BUTTON_Y", y);
|
||||
setenvd("TINT2_BUTTON_W", area->width);
|
||||
setenvd("TINT2_BUTTON_H", area->height);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_X", aligned_x);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_Y", aligned_y);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_X1", aligned_x1);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_Y1", aligned_y1);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_X2", aligned_x2);
|
||||
setenvd("TINT2_BUTTON_ALIGNED_Y2", aligned_y2);
|
||||
setenvd("TINT2_BUTTON_PANEL_X1", panel_x1);
|
||||
setenvd("TINT2_BUTTON_PANEL_Y1", panel_y1);
|
||||
setenvd("TINT2_BUTTON_PANEL_X2", panel_x2);
|
||||
setenvd("TINT2_BUTTON_PANEL_Y2", panel_y2);
|
||||
} else {
|
||||
setenv("TINT2_CONFIG", config_path, 1);
|
||||
}
|
||||
|
||||
command = g_strdup_printf("export TINT2_CONFIG=%s;"
|
||||
"%s",
|
||||
config_path,
|
||||
command);
|
||||
if (!command)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (!tooltip)
|
||||
tooltip = command;
|
||||
|
||||
#if HAVE_SN && !defined TINT2CONF
|
||||
#if HAVE_SN
|
||||
SnLauncherContext *ctx = 0;
|
||||
if (startup_notifications && time) {
|
||||
if (startup_notifications && startup_notification && time) {
|
||||
ctx = sn_launcher_context_new(server.sn_display, server.screen);
|
||||
sn_launcher_context_set_name(ctx, tooltip);
|
||||
sn_launcher_context_set_description(ctx, "Application launched from tint2");
|
||||
@@ -131,11 +384,11 @@ void tint_exec(const char *command, const char *dir, const char *tooltip, Time t
|
||||
pid_t pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "Could not fork\n");
|
||||
fprintf(stderr, "tint2: Could not fork\n");
|
||||
} else if (pid == 0) {
|
||||
// Child process
|
||||
#if HAVE_SN && !defined TINT2CONF
|
||||
if (startup_notifications && time) {
|
||||
#if HAVE_SN
|
||||
if (startup_notifications && startup_notification && time) {
|
||||
sn_launcher_context_setup_child_process(ctx);
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
@@ -144,28 +397,61 @@ void tint_exec(const char *command, const char *dir, const char *tooltip, Time t
|
||||
// Run the command
|
||||
if (dir)
|
||||
chdir(dir);
|
||||
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
|
||||
fprintf(stderr, "Failed to execlp %s\n", command);
|
||||
#if HAVE_SN && !defined TINT2CONF
|
||||
if (startup_notifications && time) {
|
||||
close_all_fds();
|
||||
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";
|
||||
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);
|
||||
}
|
||||
execlp("sh", "sh", "-c", command, NULL);
|
||||
fprintf(stderr, "tint2: Failed to execute %s\n", command);
|
||||
#if HAVE_SN
|
||||
if (startup_notifications && startup_notification && time) {
|
||||
sn_launcher_context_unref(ctx);
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
_exit(1);
|
||||
} else {
|
||||
// Parent process
|
||||
#if HAVE_SN && !defined TINT2CONF
|
||||
if (startup_notifications && time) {
|
||||
#if HAVE_SN
|
||||
if (startup_notifications && startup_notification && time) {
|
||||
g_tree_insert(server.pids, GINT_TO_POINTER(pid), ctx);
|
||||
}
|
||||
#endif // HAVE_SN
|
||||
}
|
||||
|
||||
unsetenv("TINT2_CONFIG");
|
||||
unsetenv("TINT2_BUTTON_X");
|
||||
unsetenv("TINT2_BUTTON_Y");
|
||||
unsetenv("TINT2_BUTTON_W");
|
||||
unsetenv("TINT2_BUTTON_H");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_X");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_Y");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_X1");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_Y1");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_X2");
|
||||
unsetenv("TINT2_BUTTON_ALIGNED_Y2");
|
||||
unsetenv("TINT2_BUTTON_PANEL_X1");
|
||||
unsetenv("TINT2_BUTTON_PANEL_Y1");
|
||||
unsetenv("TINT2_BUTTON_PANEL_X2");
|
||||
unsetenv("TINT2_BUTTON_PANEL_Y2");
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
void tint_exec_no_sn(const char *command)
|
||||
{
|
||||
tint_exec(command, NULL, NULL, 0);
|
||||
tint_exec(command, NULL, NULL, 0, NULL, 0, 0, FALSE, FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *expand_tilde(const char *s)
|
||||
{
|
||||
@@ -514,7 +800,7 @@ Imlib_Image load_image(const char *path, int cached)
|
||||
RsvgHandle *svg = rsvg_handle_new_from_file(path, &err);
|
||||
|
||||
if (err != NULL) {
|
||||
fprintf(stderr, "Could not load svg image!: %s", err->message);
|
||||
fprintf(stderr, "tint2: Could not load svg image!: %s", err->message);
|
||||
g_error_free(err);
|
||||
} else {
|
||||
GdkPixbuf *pixbuf = rsvg_handle_get_pixbuf(svg);
|
||||
@@ -631,41 +917,45 @@ void clear_pixmap(Pixmap p, int x, int y, int w, int h)
|
||||
XRenderFreePicture(server.display, pict);
|
||||
}
|
||||
|
||||
void get_text_size2(PangoFontDescription *font,
|
||||
void get_text_size2(const PangoFontDescription *font,
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int panel_height,
|
||||
int panel_width,
|
||||
char *text,
|
||||
int len,
|
||||
int available_height,
|
||||
int available_width,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup)
|
||||
{
|
||||
PangoRectangle rect_ink, rect;
|
||||
|
||||
Pixmap pmap = XCreatePixmap(server.display, server.root_win, panel_height, panel_width, server.depth);
|
||||
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, panel_height, panel_width);
|
||||
cairo_surface_t *cs =
|
||||
cairo_xlib_surface_create(server.display, pmap, server.visual, available_height, available_width);
|
||||
cairo_t *c = cairo_create(cs);
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
pango_layout_set_width(layout, panel_width * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, panel_height * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, available_width * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, available_height * PANGO_SCALE);
|
||||
pango_layout_set_wrap(layout, wrap);
|
||||
pango_layout_set_ellipsize(layout, ellipsis);
|
||||
pango_layout_set_font_description(layout, font);
|
||||
text_len = MAX(0, text_len);
|
||||
if (!markup)
|
||||
pango_layout_set_text(layout, text, len);
|
||||
pango_layout_set_text(layout, text, text_len);
|
||||
else
|
||||
pango_layout_set_markup(layout, text, len);
|
||||
pango_layout_set_markup(layout, text, text_len);
|
||||
|
||||
pango_layout_get_pixel_extents(layout, &rect_ink, &rect);
|
||||
*height_ink = rect_ink.height;
|
||||
*height = rect.height;
|
||||
*width = rect.width;
|
||||
// printf("dimension : %d - %d\n", rect_ink.height, rect.height);
|
||||
// fprintf(stderr, "tint2: dimension : %d - %d\n", rect_ink.height, rect.height);
|
||||
|
||||
g_object_unref(layout);
|
||||
cairo_destroy(c);
|
||||
@@ -740,3 +1030,28 @@ gint cmp_ptr(gconstpointer a, gconstpointer b)
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void close_all_fds()
|
||||
{
|
||||
long maxfd = sysconf(_SC_OPEN_MAX);
|
||||
for (int fd = 3; fd < maxfd; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
GString *tint2_g_string_replace(GString *s, const char *from, const char *to)
|
||||
{
|
||||
GString *result = g_string_new("");
|
||||
for (char *p = s->str; *p;) {
|
||||
if (strstr(p, from) == p) {
|
||||
g_string_append(result, to);
|
||||
p += strlen(from);
|
||||
} else {
|
||||
g_string_append_c(result, *p);
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
g_string_assign(s, result->str);
|
||||
g_string_free(result, TRUE);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,18 @@ typedef enum MouseAction {
|
||||
|
||||
#define ALL_DESKTOPS 0xFFFFFFFF
|
||||
|
||||
void write_string(int fd, const char *s);
|
||||
void log_string(int fd, const char *s);
|
||||
|
||||
void dump_backtrace(int log_fd);
|
||||
|
||||
// sleep() returns early when signals arrive. This function does not.
|
||||
void safe_sleep(int seconds);
|
||||
|
||||
const char *signal_name(int sig);
|
||||
|
||||
const char *get_home_dir();
|
||||
|
||||
// Copies a file to another path
|
||||
void copy_file(const char *path_src, const char *path_dest);
|
||||
|
||||
@@ -54,8 +66,17 @@ void extract_values(const char *value, char **value1, char **value2, char **valu
|
||||
void extract_values_4(const char *value, char **value1, char **value2, char **value3, char **value4);
|
||||
|
||||
// Executes a command in a shell.
|
||||
void tint_exec(const char *command, const char *dir, const char *tooltip, Time time);
|
||||
pid_t tint_exec(const char *command,
|
||||
const char *dir,
|
||||
const char *tooltip,
|
||||
Time time,
|
||||
Area *area,
|
||||
int x,
|
||||
int y,
|
||||
gboolean terminal,
|
||||
gboolean startup_notification);
|
||||
void tint_exec_no_sn(const char *command);
|
||||
int setenvd(const char *name, const int value);
|
||||
|
||||
// Returns a copy of s in which "~" is expanded to the path to the user's home directory.
|
||||
// The caller takes ownership of the string.
|
||||
@@ -94,14 +115,14 @@ void create_heuristic_mask(DATA32 *data, int w, int h);
|
||||
// Renders the current Imlib image to a drawable. Wrapper around imlib_render_image_on_drawable.
|
||||
void render_image(Drawable d, int x, int y);
|
||||
|
||||
void get_text_size2(PangoFontDescription *font,
|
||||
void get_text_size2(const PangoFontDescription *font,
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int panel_height,
|
||||
int panel_with,
|
||||
char *text,
|
||||
int len,
|
||||
int available_height,
|
||||
int available_with,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup);
|
||||
@@ -115,6 +136,8 @@ void draw_rect_on_sides(cairo_t *c, double x, double y, double w, double h, doub
|
||||
// Clears the pixmap (with transparent color)
|
||||
void clear_pixmap(Pixmap p, int x, int y, int w, int h);
|
||||
|
||||
void close_all_fds();
|
||||
|
||||
// Appends to the list locations all the directories contained in the environment variable var (split by ":").
|
||||
// Optional suffixes are added to each directory. The suffix arguments MUST end with NULL.
|
||||
// Returns the new value of the list.
|
||||
@@ -125,6 +148,8 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr
|
||||
// A trivial pointer comparator.
|
||||
gint cmp_ptr(gconstpointer a, gconstpointer b);
|
||||
|
||||
GString *tint2_g_string_replace(GString *s, const char *from, const char *to);
|
||||
|
||||
#define free_and_null(p) \
|
||||
{ \
|
||||
free(p); \
|
||||
|
||||
97
src/util/fps_distribution.c
Normal file
97
src/util/fps_distribution.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2017 tint2 authors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fps_distribution.h"
|
||||
|
||||
static float *fps_distribution = NULL;
|
||||
|
||||
void init_fps_distribution()
|
||||
{
|
||||
// measure FPS with resolution:
|
||||
// 0-59: 1 (60 samples)
|
||||
// 60-199: 10 (14)
|
||||
// 200-1,999: 25 (72)
|
||||
// 1k-19,999: 1000 (19)
|
||||
// 20x+: inf (1)
|
||||
// => 166 samples
|
||||
if (fps_distribution)
|
||||
return;
|
||||
fps_distribution = calloc(170, sizeof(float));
|
||||
}
|
||||
|
||||
void cleanup_fps_distribution()
|
||||
{
|
||||
free(fps_distribution);
|
||||
fps_distribution = NULL;
|
||||
}
|
||||
|
||||
void sample_fps(double fps)
|
||||
{
|
||||
int fps_rounded = (int)(fps + 0.5);
|
||||
int i = 1;
|
||||
if (fps_rounded < 60) {
|
||||
i += fps_rounded;
|
||||
} else {
|
||||
i += 60;
|
||||
if (fps_rounded < 200) {
|
||||
i += (fps_rounded - 60) / 10;
|
||||
} else {
|
||||
i += 14;
|
||||
if (fps_rounded < 2000) {
|
||||
i += (fps_rounded - 200) / 25;
|
||||
} else {
|
||||
i += 72;
|
||||
if (fps_rounded < 20000) {
|
||||
i += (fps_rounded - 2000) / 1000;
|
||||
} else {
|
||||
i += 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fprintf(stderr, "tint2: fps = %.0f => i = %d\n", fps, i);
|
||||
fps_distribution[i] += 1.;
|
||||
fps_distribution[0] += 1.;
|
||||
}
|
||||
|
||||
void fps_compute_stats(double *low, double *median, double *high, double *samples)
|
||||
{
|
||||
*median = *low = *high = *samples = -1;
|
||||
if (!fps_distribution || fps_distribution[0] < 1)
|
||||
return;
|
||||
float total = fps_distribution[0];
|
||||
*samples = (double)fps_distribution[0];
|
||||
float cum_low = 0.05f * total;
|
||||
float cum_median = 0.5f * total;
|
||||
float cum_high = 0.95f * total;
|
||||
float cum = 0;
|
||||
for (int i = 1; i <= 166; i++) {
|
||||
double value =
|
||||
(i < 60) ? i : (i < 74) ? (60 + (i - 60) * 10) : (i < 146) ? (200 + (i - 74) * 25)
|
||||
: (i < 165) ? (2000 + (i - 146) * 1000) : 20000;
|
||||
// fprintf(stderr, "tint2: %6.0f (i = %3d) : %.0f | ", value, i, (double)fps_distribution[i]);
|
||||
cum += fps_distribution[i];
|
||||
if (*low < 0 && cum >= cum_low)
|
||||
*low = value;
|
||||
if (*median < 0 && cum >= cum_median)
|
||||
*median = value;
|
||||
if (*high < 0 && cum >= cum_high)
|
||||
*high = value;
|
||||
}
|
||||
}
|
||||
9
src/util/fps_distribution.h
Normal file
9
src/util/fps_distribution.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef FPS_DISTRIBUTION_H
|
||||
#define FPS_DISTRIBUTION_H
|
||||
|
||||
void init_fps_distribution();
|
||||
void cleanup_fps_distribution();
|
||||
void sample_fps(double fps);
|
||||
void fps_compute_stats(double *low, double *median, double *high, double *samples);
|
||||
|
||||
#endif
|
||||
@@ -40,7 +40,7 @@ GradientType gradient_type_from_string(const char *str)
|
||||
return GRADIENT_VERTICAL;
|
||||
if (g_str_equal(str, "radial"))
|
||||
return GRADIENT_CENTERED;
|
||||
fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str);
|
||||
fprintf(stderr, RED "tint2: Invalid gradient type: %s" RESET "\n", str);
|
||||
return GRADIENT_VERTICAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,11 +67,10 @@ void cleanup_gradient(GradientClass *g);
|
||||
// Gradient instances associated to Areas
|
||||
|
||||
struct Area;
|
||||
typedef struct Area Area;
|
||||
|
||||
typedef struct GradientInstance {
|
||||
GradientClass *gradient_class;
|
||||
Area *area;
|
||||
struct Area *area;
|
||||
cairo_pattern_t *pattern;
|
||||
} GradientInstance;
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ struct _timeout {
|
||||
void *arg;
|
||||
multi_timeout *multi_timeout;
|
||||
timeout **self;
|
||||
gboolean expired;
|
||||
};
|
||||
|
||||
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t);
|
||||
@@ -82,6 +83,16 @@ void cleanup_timeout()
|
||||
}
|
||||
}
|
||||
|
||||
int gettime(struct timespec *tp)
|
||||
{
|
||||
// CLOCK_BOOTTIME under Linux is the same as CLOCK_MONOTONIC under *BSD.
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
return clock_gettime(CLOCK_BOOTTIME, tp);
|
||||
#else
|
||||
return clock_gettime(CLOCK_MONOTONIC, tp);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implementation notes for timeouts
|
||||
//
|
||||
// The timeouts are kept in a GSList sorted by their expiration time.
|
||||
@@ -96,7 +107,7 @@ void cleanup_timeout()
|
||||
|
||||
timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self)
|
||||
{
|
||||
if (self && *self)
|
||||
if (self && *self && !(*self)->expired)
|
||||
return *self;
|
||||
timeout *t = calloc(1, sizeof(timeout));
|
||||
t->self = self;
|
||||
@@ -118,13 +129,13 @@ void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_call
|
||||
}
|
||||
}
|
||||
|
||||
void update_next_timeout()
|
||||
struct timeval *get_next_timeout()
|
||||
{
|
||||
if (timeout_list) {
|
||||
timeout *t = timeout_list->data;
|
||||
struct timespec cur_time;
|
||||
struct timespec next_timeout2 = {.tv_sec = next_timeout.tv_sec, .tv_nsec = next_timeout.tv_usec * 1000};
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) {
|
||||
next_timeout.tv_sec = 0;
|
||||
next_timeout.tv_usec = 0;
|
||||
@@ -134,17 +145,19 @@ void update_next_timeout()
|
||||
}
|
||||
} else
|
||||
next_timeout.tv_sec = -1;
|
||||
return (next_timeout.tv_sec >= 0 && next_timeout.tv_usec >= 0) ? &next_timeout : NULL;
|
||||
}
|
||||
|
||||
void callback_timeout_expired()
|
||||
void handle_expired_timers()
|
||||
{
|
||||
struct timespec cur_time;
|
||||
timeout *t;
|
||||
while (timeout_list) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
t = timeout_list->data;
|
||||
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
|
||||
// it's time for the callback function
|
||||
t->expired = t->interval_msec == 0;
|
||||
t->_callback(t->arg);
|
||||
// If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list
|
||||
if (g_slist_find(timeout_list, t)) {
|
||||
@@ -187,7 +200,7 @@ void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(),
|
||||
t->_callback = _callback;
|
||||
t->arg = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
t->timeout_expires = add_msec_to_timespec(cur_time, value_msec);
|
||||
|
||||
int can_align = 0;
|
||||
@@ -343,7 +356,7 @@ void update_multi_timeout_values(multi_timeout_handler *mth)
|
||||
int next_timeout_msec = interval;
|
||||
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
|
||||
GSList *it = mth->timeout_list;
|
||||
struct timespec diff_time;
|
||||
@@ -368,7 +381,7 @@ void callback_multi_timeout(void *arg)
|
||||
{
|
||||
multi_timeout_handler *mth = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
GSList *it = mth->timeout_list;
|
||||
while (it) {
|
||||
timeout *t = it->data;
|
||||
@@ -407,7 +420,7 @@ void remove_from_multi_timeout(timeout *t)
|
||||
free(mth);
|
||||
|
||||
struct timespec cur_time, diff_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
timespec_subtract(&diff_time, &t->timeout_expires, &cur_time);
|
||||
int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000;
|
||||
add_timeout_intern(msec_to_expiration,
|
||||
@@ -438,7 +451,7 @@ double profiling_get_time_old_time = 0;
|
||||
double get_time()
|
||||
{
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
gettime(&cur_time);
|
||||
return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
// Periodic timeouts are aligned to each other whenever possible, i.e. one interval_msec is an
|
||||
// integral multiple of the other.
|
||||
|
||||
extern struct timeval next_timeout;
|
||||
typedef struct _timeout timeout;
|
||||
|
||||
// Initializes default global data.
|
||||
@@ -54,11 +53,12 @@ void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_call
|
||||
// Stops the timer 't'
|
||||
void stop_timeout(timeout *t);
|
||||
|
||||
// Updates next_timeout to the value, when the next installed timeout will expire
|
||||
void update_next_timeout();
|
||||
// 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();
|
||||
|
||||
// Callback of all expired timeouts
|
||||
void callback_timeout_expired();
|
||||
void handle_expired_timers();
|
||||
|
||||
// Returns -1 if t1 < t2, 0 if t1 == t2, 1 if t1 > t2
|
||||
gint compare_timespecs(const struct timespec *t1, const struct timespec *t2);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include "uevent.h"
|
||||
int uevent_fd = -1;
|
||||
|
||||
#ifdef ENABLE_UEVENT
|
||||
|
||||
#include <string.h>
|
||||
@@ -30,9 +33,7 @@
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "uevent.h"
|
||||
|
||||
static int ueventfd = -1;
|
||||
static struct sockaddr_nl nls;
|
||||
static GList *notifiers = NULL;
|
||||
|
||||
@@ -146,11 +147,11 @@ void uevent_unregister_notifier(struct uevent_notify *nb)
|
||||
|
||||
void uevent_handler()
|
||||
{
|
||||
if (ueventfd < 0)
|
||||
if (uevent_fd < 0)
|
||||
return;
|
||||
|
||||
char buf[512];
|
||||
int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
int len = recv(uevent_fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
@@ -181,27 +182,27 @@ int uevent_init()
|
||||
nls.nl_groups = -1;
|
||||
|
||||
/* open socket */
|
||||
ueventfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (ueventfd < 0) {
|
||||
fprintf(stderr, "Error: socket open failed\n");
|
||||
uevent_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (uevent_fd < 0) {
|
||||
fprintf(stderr, "tint2: Error: socket open failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Listen to netlink socket */
|
||||
if (bind(ueventfd, (void *)&nls, sizeof(struct sockaddr_nl))) {
|
||||
fprintf(stderr, "Bind failed\n");
|
||||
if (bind(uevent_fd, (void *)&nls, sizeof(struct sockaddr_nl))) {
|
||||
fprintf(stderr, "tint2: Bind failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Kernel uevent interface initialized...\n");
|
||||
fprintf(stderr, "tint2: Kernel uevent interface initialized...\n");
|
||||
|
||||
return ueventfd;
|
||||
return uevent_fd;
|
||||
}
|
||||
|
||||
void uevent_cleanup()
|
||||
{
|
||||
if (ueventfd >= 0)
|
||||
close(ueventfd);
|
||||
if (uevent_fd >= 0)
|
||||
close(uevent_fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef UEVENT_H
|
||||
#define UEVENT_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
enum uevent_action {
|
||||
UEVENT_UNKNOWN = 0x01,
|
||||
UEVENT_ADD = 0x02,
|
||||
@@ -48,6 +50,8 @@ struct uevent_notify {
|
||||
void (*cb)(struct uevent *e, void *userdata);
|
||||
};
|
||||
|
||||
extern int uevent_fd;
|
||||
|
||||
#if ENABLE_UEVENT
|
||||
int uevent_init();
|
||||
void uevent_cleanup();
|
||||
|
||||
@@ -157,7 +157,7 @@ int get_window_desktop(Window win)
|
||||
|
||||
if (best_match < 0)
|
||||
best_match = 0;
|
||||
// fprintf(stderr, "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;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ int get_window_monitor(Window win)
|
||||
|
||||
if (best_match < 0)
|
||||
best_match = 0;
|
||||
// fprintf(stderr, "desktop %d, window %lx %s : monitor %d, (%d, %d)\n", 1 + get_current_desktop(), win,
|
||||
// fprintf(stderr, "tint2: desktop %d, window %lx %s : monitor %d, (%d, %d)\n", 1 + get_current_desktop(), win,
|
||||
// get_task(win) ? get_task(win)->title : "??", best_match+1, x, y);
|
||||
return best_match;
|
||||
}
|
||||
@@ -277,6 +277,9 @@ 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)
|
||||
{
|
||||
if (icon_count < 1 || num < 1)
|
||||
return NULL;
|
||||
|
||||
int width[icon_count], height[icon_count], pos, i, w, h;
|
||||
gulong *icon_data[icon_count];
|
||||
|
||||
|
||||
231
test/configs/compton.conf
Normal file
231
test/configs/compton.conf
Normal file
@@ -0,0 +1,231 @@
|
||||
#################################
|
||||
#
|
||||
# Backend
|
||||
#
|
||||
#################################
|
||||
|
||||
# Backend to use: "xrender" or "glx".
|
||||
# GLX backend is typically much faster but depends on a sane driver.
|
||||
backend = "glx";
|
||||
|
||||
#################################
|
||||
#
|
||||
# GLX backend
|
||||
#
|
||||
#################################
|
||||
|
||||
glx-no-stencil = true;
|
||||
|
||||
# GLX backend: Copy unmodified regions from front buffer instead of redrawing them all.
|
||||
# My tests with nvidia-drivers show a 10% decrease in performance when the whole screen is modified,
|
||||
# but a 20% increase when only 1/4 is.
|
||||
# My tests on nouveau show terrible slowdown.
|
||||
# Useful with --glx-swap-method, as well.
|
||||
glx-copy-from-front = false;
|
||||
|
||||
# GLX backend: Use MESA_copy_sub_buffer to do partial screen update.
|
||||
# My tests on nouveau shows a 200% performance boost when only 1/4 of the screen is updated.
|
||||
# May break VSync and is not available on some drivers.
|
||||
# Overrides --glx-copy-from-front.
|
||||
# glx-use-copysubbuffermesa = true;
|
||||
|
||||
# GLX backend: Avoid rebinding pixmap on window damage.
|
||||
# Probably could improve performance on rapid window content changes, but is known to break things on some drivers (LLVMpipe).
|
||||
# Recommended if it works.
|
||||
# glx-no-rebind-pixmap = true;
|
||||
|
||||
|
||||
# GLX backend: GLX buffer swap method we assume.
|
||||
# Could be undefined (0), copy (1), exchange (2), 3-6, or buffer-age (-1).
|
||||
# undefined is the slowest and the safest, and the default value.
|
||||
# copy is fastest, but may fail on some drivers,
|
||||
# 2-6 are gradually slower but safer (6 is still faster than 0).
|
||||
# Usually, double buffer means 2, triple buffer means 3.
|
||||
# buffer-age means auto-detect using GLX_EXT_buffer_age, supported by some drivers.
|
||||
# Useless with --glx-use-copysubbuffermesa.
|
||||
# Partially breaks --resize-damage.
|
||||
# Defaults to undefined.
|
||||
glx-swap-method = "undefined";
|
||||
|
||||
#################################
|
||||
#
|
||||
# Shadows
|
||||
#
|
||||
#################################
|
||||
|
||||
# Enabled client-side shadows on windows.
|
||||
shadow = true;
|
||||
# Don't draw shadows on DND windows.
|
||||
no-dnd-shadow = true;
|
||||
# Avoid drawing shadows on dock/panel windows.
|
||||
no-dock-shadow = true;
|
||||
# Zero the part of the shadow's mask behind the window. Fix some weirdness with ARGB windows.
|
||||
clear-shadow = true;
|
||||
# The blur radius for shadows. (default 12)
|
||||
shadow-radius = 10;
|
||||
# The left offset for shadows. (default -15)
|
||||
shadow-offset-x = -12;
|
||||
# The top offset for shadows. (default -15)
|
||||
shadow-offset-y = -12;
|
||||
# The translucency for shadows. (default .75)
|
||||
shadow-opacity = 0.75;
|
||||
|
||||
# Set if you want different colour shadows
|
||||
# shadow-red = 0.0;
|
||||
# shadow-green = 0.0;
|
||||
# shadow-blue = 0.0;
|
||||
|
||||
# The shadow exclude options are helpful if you have shadows enabled. Due to the way compton draws its shadows, certain applications will have visual glitches
|
||||
# (most applications are fine, only apps that do weird things with xshapes or argb are affected).
|
||||
# This list includes all the affected apps I found in my testing. The "! name~=''" part excludes shadows on any "Unknown" windows, this prevents a visual glitch with the XFWM alt tab switcher.
|
||||
shadow-exclude = [
|
||||
"! name~=''",
|
||||
"name = 'Notification'",
|
||||
"name = 'Plank'",
|
||||
"name = 'Docky'",
|
||||
"name = 'Kupfer'",
|
||||
"name = 'xfce4-notifyd'",
|
||||
"name *= 'VLC'",
|
||||
"name *= 'compton'",
|
||||
"name *= 'Chromium'",
|
||||
"name *= 'Chrome'",
|
||||
"name *= 'Firefox'",
|
||||
"class_g = 'Conky'",
|
||||
"class_g = 'Kupfer'",
|
||||
"class_g = 'Synapse'",
|
||||
"class_g ?= 'Notify-osd'",
|
||||
"class_g ?= 'Cairo-dock'",
|
||||
"class_g ?= 'Xfce4-notifyd'",
|
||||
"class_g ?= 'Xfce4-power-manager'"
|
||||
];
|
||||
# Avoid drawing shadow on all shaped windows (see also: --detect-rounded-corners)
|
||||
shadow-ignore-shaped = false;
|
||||
|
||||
#################################
|
||||
#
|
||||
# Opacity
|
||||
#
|
||||
#################################
|
||||
|
||||
menu-opacity = 1;
|
||||
inactive-opacity = 1;
|
||||
active-opacity = 1;
|
||||
frame-opacity = 1;
|
||||
inactive-opacity-override = false;
|
||||
alpha-step = 0.06;
|
||||
|
||||
# Dim inactive windows. (0.0 - 1.0)
|
||||
# inactive-dim = 0.2;
|
||||
# Do not let dimness adjust based on window opacity.
|
||||
# inactive-dim-fixed = true;
|
||||
# Blur background of transparent windows. Bad performance with X Render backend. GLX backend is preferred.
|
||||
# blur-background = true;
|
||||
# Blur background of opaque windows with transparent frames as well.
|
||||
# blur-background-frame = true;
|
||||
# Do not let blur radius adjust based on window opacity.
|
||||
blur-background-fixed = false;
|
||||
blur-background-exclude = [
|
||||
"window_type = 'dock'",
|
||||
"window_type = 'desktop'"
|
||||
];
|
||||
|
||||
#################################
|
||||
#
|
||||
# Fading
|
||||
#
|
||||
#################################
|
||||
|
||||
# Fade windows during opacity changes.
|
||||
fading = false;
|
||||
# The time between steps in a fade in milliseconds. (default 10).
|
||||
fade-delta = 4;
|
||||
# Opacity change between steps while fading in. (default 0.028).
|
||||
fade-in-step = 0.03;
|
||||
# Opacity change between steps while fading out. (default 0.03).
|
||||
fade-out-step = 0.03;
|
||||
# Fade windows in/out when opening/closing
|
||||
# no-fading-openclose = true;
|
||||
|
||||
# Specify a list of conditions of windows that should not be faded.
|
||||
fade-exclude = [ ];
|
||||
|
||||
#################################
|
||||
#
|
||||
# Other
|
||||
#
|
||||
#################################
|
||||
|
||||
# Try to detect WM windows and mark them as active.
|
||||
mark-wmwin-focused = true;
|
||||
# Mark all non-WM but override-redirect windows active (e.g. menus).
|
||||
mark-ovredir-focused = true;
|
||||
# Use EWMH _NET_WM_ACTIVE_WINDOW to determine which window is focused instead of using FocusIn/Out events.
|
||||
# Usually more reliable but depends on a EWMH-compliant WM.
|
||||
use-ewmh-active-win = true;
|
||||
# Detect rounded corners and treat them as rectangular when --shadow-ignore-shaped is on.
|
||||
detect-rounded-corners = true;
|
||||
|
||||
# Detect _NET_WM_OPACITY on client windows, useful for window managers not passing _NET_WM_OPACITY of client windows to frame windows.
|
||||
# This prevents opacity being ignored for some apps.
|
||||
# For example without this enabled my xfce4-notifyd is 100% opacity no matter what.
|
||||
detect-client-opacity = true;
|
||||
|
||||
# Specify refresh rate of the screen.
|
||||
# If not specified or 0, compton will try detecting this with X RandR extension.
|
||||
refresh-rate = 0;
|
||||
|
||||
# Set VSync method. VSync methods currently available:
|
||||
# none: No VSync
|
||||
# drm: VSync with DRM_IOCTL_WAIT_VBLANK. May only work on some drivers.
|
||||
# opengl: Try to VSync with SGI_video_sync OpenGL extension. Only work on some drivers.
|
||||
# opengl-oml: Try to VSync with OML_sync_control OpenGL extension. Only work on some drivers.
|
||||
# opengl-swc: Try to VSync with SGI_swap_control OpenGL extension. Only work on some drivers. Works only with GLX backend. Known to be most effective on many drivers. Does not actually control paint timing, only buffer swap is affected, so it doesn’t have the effect of --sw-opti unlike other methods. Experimental.
|
||||
# opengl-mswc: Try to VSync with MESA_swap_control OpenGL extension. Basically the same as opengl-swc above, except the extension we use.
|
||||
# (Note some VSync methods may not be enabled at compile time.)
|
||||
vsync = "opengl-swc";
|
||||
|
||||
# Enable DBE painting mode, intended to use with VSync to (hopefully) eliminate tearing.
|
||||
# Reported to have no effect, though.
|
||||
dbe = false;
|
||||
# Painting on X Composite overlay window. Recommended.
|
||||
paint-on-overlay = true;
|
||||
|
||||
# Limit compton to repaint at most once every 1 / refresh_rate second to boost performance.
|
||||
# This should not be used with --vsync drm/opengl/opengl-oml as they essentially does --sw-opti's job already,
|
||||
# unless you wish to specify a lower refresh rate than the actual value.
|
||||
sw-opti = false;
|
||||
|
||||
# Unredirect all windows if a full-screen opaque window is detected, to maximize performance for full-screen windows, like games.
|
||||
# Known to cause flickering when redirecting/unredirecting windows.
|
||||
# paint-on-overlay may make the flickering less obvious.
|
||||
unredir-if-possible = true;
|
||||
|
||||
# Specify a list of conditions of windows that should always be considered focused.
|
||||
focus-exclude = [ ];
|
||||
|
||||
# Use WM_TRANSIENT_FOR to group windows, and consider windows in the same group focused at the same time.
|
||||
detect-transient = true;
|
||||
# Use WM_CLIENT_LEADER to group windows, and consider windows in the same group focused at the same time.
|
||||
# WM_TRANSIENT_FOR has higher priority if --detect-transient is enabled, too.
|
||||
detect-client-leader = true;
|
||||
|
||||
#################################
|
||||
#
|
||||
# Window type settings
|
||||
#
|
||||
#################################
|
||||
|
||||
wintypes:
|
||||
{
|
||||
tooltip =
|
||||
{
|
||||
# fade: Fade the particular type of windows.
|
||||
fade = false;
|
||||
# shadow: Give those windows shadow
|
||||
shadow = false;
|
||||
# opacity: Default opacity for the type of windows.
|
||||
opacity = 1;
|
||||
# focus: Whether to always consider windows of this type focused.
|
||||
focus = true;
|
||||
};
|
||||
};
|
||||
743
test/configs/openbox.xml
Normal file
743
test/configs/openbox.xml
Normal file
@@ -0,0 +1,743 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Do not edit this file, it will be overwritten on install.
|
||||
Copy the file to $HOME/.config/openbox/ instead. -->
|
||||
|
||||
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<resistance>
|
||||
<strength>10</strength>
|
||||
<screen_edge_strength>20</screen_edge_strength>
|
||||
</resistance>
|
||||
|
||||
<focus>
|
||||
<focusNew>yes</focusNew>
|
||||
<!-- always try to focus new windows when they appear. other rules do
|
||||
apply -->
|
||||
<followMouse>no</followMouse>
|
||||
<!-- move focus to a window when you move the mouse into it -->
|
||||
<focusLast>yes</focusLast>
|
||||
<!-- focus the last used window when changing desktops, instead of the one
|
||||
under the mouse pointer. when followMouse is enabled -->
|
||||
<underMouse>no</underMouse>
|
||||
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||
<focusDelay>200</focusDelay>
|
||||
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||
<raiseOnFocus>no</raiseOnFocus>
|
||||
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||
mouse into it, also raise the window -->
|
||||
</focus>
|
||||
|
||||
<placement>
|
||||
<policy>Smart</policy>
|
||||
<!-- 'Smart' or 'UnderMouse' -->
|
||||
<center>yes</center>
|
||||
<!-- whether to place windows in the center of the free area found or
|
||||
the top left corner -->
|
||||
<monitor>Primary</monitor>
|
||||
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||
the active window is, 'Primary' - only on the primary monitor -->
|
||||
<primaryMonitor>1</primaryMonitor>
|
||||
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||
focus cycling popup, or the desktop switch popup. It can be an index
|
||||
from 1, specifying a particular monitor. Or it can be one of the
|
||||
following: 'Mouse' - where the mouse is, or
|
||||
'Active' - where the active window is -->
|
||||
</placement>
|
||||
|
||||
<theme>
|
||||
<name>Clearlooks</name>
|
||||
<titleLayout>NLIMC</titleLayout>
|
||||
<!--
|
||||
available characters are NDSLIMC, each can occur at most once.
|
||||
N: window icon
|
||||
L: window label (AKA title).
|
||||
I: iconify
|
||||
M: maximize
|
||||
C: close
|
||||
S: shade (roll up/down)
|
||||
D: omnipresent (on all desktops).
|
||||
-->
|
||||
<keepBorder>yes</keepBorder>
|
||||
<animateIconify>yes</animateIconify>
|
||||
<font place="ActiveWindow">
|
||||
<name>sans</name>
|
||||
<size>8</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="InactiveWindow">
|
||||
<name>sans</name>
|
||||
<size>8</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="MenuHeader">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>normal</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="MenuItem">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>normal</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="ActiveOnScreenDisplay">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
<font place="InactiveOnScreenDisplay">
|
||||
<name>sans</name>
|
||||
<size>9</size>
|
||||
<!-- font size in points -->
|
||||
<weight>bold</weight>
|
||||
<!-- 'bold' or 'normal' -->
|
||||
<slant>normal</slant>
|
||||
<!-- 'italic' or 'normal' -->
|
||||
</font>
|
||||
</theme>
|
||||
|
||||
<desktops>
|
||||
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||
during a session
|
||||
|
||||
these are default values to use when other ones are not already set
|
||||
by other applications, or saved in your session
|
||||
|
||||
use obconf if you want to change these without having to log out
|
||||
and back in -->
|
||||
<number>4</number>
|
||||
<firstdesk>1</firstdesk>
|
||||
<names>
|
||||
<!-- set names up here if you want to, like this:
|
||||
<name>desktop 1</name>
|
||||
<name>desktop 2</name>
|
||||
-->
|
||||
</names>
|
||||
<popupTime>875</popupTime>
|
||||
<!-- The number of milliseconds to show the popup for when switching
|
||||
desktops. Set this to 0 to disable the popup. -->
|
||||
</desktops>
|
||||
|
||||
<resize>
|
||||
<drawContents>yes</drawContents>
|
||||
<popupShow>Nonpixel</popupShow>
|
||||
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||
<popupPosition>Center</popupPosition>
|
||||
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||
<popupFixedPosition>
|
||||
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||
|
||||
<x>10</x>
|
||||
<!-- positive number for distance from left edge, negative number for
|
||||
distance from right edge, or 'Center' -->
|
||||
<y>10</y>
|
||||
<!-- positive number for distance from top edge, negative number for
|
||||
distance from bottom edge, or 'Center' -->
|
||||
</popupFixedPosition>
|
||||
</resize>
|
||||
|
||||
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||
they are maximized, or when they are initially placed.
|
||||
Many programs reserve space automatically, but you can use this in other
|
||||
cases. -->
|
||||
<margins>
|
||||
<top>0</top>
|
||||
<bottom>0</bottom>
|
||||
<left>0</left>
|
||||
<right>0</right>
|
||||
</margins>
|
||||
|
||||
<dock>
|
||||
<position>TopLeft</position>
|
||||
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||
<floatingX>0</floatingX>
|
||||
<floatingY>0</floatingY>
|
||||
<noStrut>no</noStrut>
|
||||
<stacking>Above</stacking>
|
||||
<!-- 'Above', 'Normal', or 'Below' -->
|
||||
<direction>Vertical</direction>
|
||||
<!-- 'Vertical' or 'Horizontal' -->
|
||||
<autoHide>no</autoHide>
|
||||
<hideDelay>300</hideDelay>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<showDelay>300</showDelay>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<moveButton>Middle</moveButton>
|
||||
<!-- 'Left', 'Middle', 'Right' -->
|
||||
</dock>
|
||||
|
||||
<keyboard>
|
||||
<chainQuitKey>C-g</chainQuitKey>
|
||||
|
||||
<!-- Keybindings for desktop switching -->
|
||||
<keybind key="C-A-Left">
|
||||
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Right">
|
||||
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Up">
|
||||
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Down">
|
||||
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Left">
|
||||
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Right">
|
||||
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Up">
|
||||
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="S-A-Down">
|
||||
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||
</keybind>
|
||||
<keybind key="W-F1">
|
||||
<action name="GoToDesktop"><to>1</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F2">
|
||||
<action name="GoToDesktop"><to>2</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F3">
|
||||
<action name="GoToDesktop"><to>3</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-F4">
|
||||
<action name="GoToDesktop"><to>4</to></action>
|
||||
</keybind>
|
||||
<keybind key="W-d">
|
||||
<action name="ToggleShowDesktop"/>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for windows -->
|
||||
<keybind key="A-F4">
|
||||
<action name="Close"/>
|
||||
</keybind>
|
||||
<keybind key="A-Escape">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</keybind>
|
||||
<keybind key="A-space">
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for window switching -->
|
||||
<keybind key="A-Tab">
|
||||
<action name="NextWindow">
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="A-S-Tab">
|
||||
<action name="PreviousWindow">
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="C-A-Tab">
|
||||
<action name="NextWindow">
|
||||
<panels>yes</panels><desktop>yes</desktop>
|
||||
<finalactions>
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</finalactions>
|
||||
</action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for window switching with the arrow keys -->
|
||||
<keybind key="W-S-Right">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>right</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Left">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>left</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Up">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>up</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
<keybind key="W-S-Down">
|
||||
<action name="DirectionalCycleWindows">
|
||||
<direction>down</direction>
|
||||
</action>
|
||||
</keybind>
|
||||
|
||||
<!-- Keybindings for running applications -->
|
||||
<keybind key="W-e">
|
||||
<action name="Execute">
|
||||
<startupnotify>
|
||||
<enabled>true</enabled>
|
||||
<name>Konqueror</name>
|
||||
</startupnotify>
|
||||
<command>kfmclient openProfile filemanagement</command>
|
||||
</action>
|
||||
</keybind>
|
||||
</keyboard>
|
||||
|
||||
<mouse>
|
||||
<dragThreshold>1</dragThreshold>
|
||||
<!-- number of pixels the mouse must move before a drag begins -->
|
||||
<doubleClickTime>500</doubleClickTime>
|
||||
<!-- in milliseconds (1000 = 1 second) -->
|
||||
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||
Set this to 0 to disable warping -->
|
||||
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||
switching due to hitting the edge of the screen -->
|
||||
|
||||
<context name="Frame">
|
||||
<mousebind button="A-Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="Click">
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Left" action="Drag">
|
||||
<action name="Move"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="A-Right" action="Drag">
|
||||
<action name="Resize"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Middle" action="Press">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-S-Up" action="Click">
|
||||
<action name="SendToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-S-Down" action="Click">
|
||||
<action name="SendToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Titlebar">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Move"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="DoubleClick">
|
||||
<action name="ToggleMaximize"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="if">
|
||||
<shaded>no</shaded>
|
||||
<then>
|
||||
<action name="Shade"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
<action name="Lower"/>
|
||||
</then>
|
||||
</action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="if">
|
||||
<shaded>yes</shaded>
|
||||
<then>
|
||||
<action name="Unshade"/>
|
||||
<action name="Raise"/>
|
||||
</then>
|
||||
</action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Lower"/>
|
||||
<action name="FocusToBottom"/>
|
||||
<action name="Unfocus"/>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Top">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>top</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Left">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>left</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Right">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>right</edge></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Bottom">
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"><edge>bottom</edge></action>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Drag">
|
||||
<action name="Resize"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Client">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Icon">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="AllDesktops">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleOmnipresent"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Shade">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleShade"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Iconify">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="Iconify"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Maximize">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="ToggleMaximize"/>
|
||||
</mousebind>
|
||||
<mousebind button="Middle" action="Click">
|
||||
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Click">
|
||||
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Close">
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
<action name="Unshade"/>
|
||||
</mousebind>
|
||||
<mousebind button="Left" action="Click">
|
||||
<action name="Close"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Desktop">
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="C-A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
|
||||
<mousebind button="Left" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="Focus"/>
|
||||
<action name="Raise"/>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="Root">
|
||||
<!-- Menus -->
|
||||
<mousebind button="Middle" action="Press">
|
||||
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||
</mousebind>
|
||||
<mousebind button="Right" action="Press">
|
||||
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
|
||||
<context name="MoveResize">
|
||||
<mousebind button="Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Up" action="Click">
|
||||
<action name="GoToDesktop"><to>previous</to></action>
|
||||
</mousebind>
|
||||
<mousebind button="A-Down" action="Click">
|
||||
<action name="GoToDesktop"><to>next</to></action>
|
||||
</mousebind>
|
||||
</context>
|
||||
</mouse>
|
||||
|
||||
<menu>
|
||||
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||
|
||||
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||
<file>menu.xml</file>
|
||||
<hideDelay>200</hideDelay>
|
||||
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||
menu is hidden again -->
|
||||
<middle>no</middle>
|
||||
<!-- center submenus vertically about the parent entry -->
|
||||
<submenuShowDelay>100</submenuShowDelay>
|
||||
<!-- time to delay before showing a submenu after hovering over the parent
|
||||
entry.
|
||||
if this is a negative value, then the delay is infinite and the
|
||||
submenu will not be shown until it is clicked on -->
|
||||
<submenuHideDelay>400</submenuHideDelay>
|
||||
<!-- time to delay before hiding a submenu when selecting another
|
||||
entry in parent menu
|
||||
if this is a negative value, then the delay is infinite and the
|
||||
submenu will not be hidden until a different submenu is opened -->
|
||||
<showIcons>yes</showIcons>
|
||||
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||
<manageDesktops>yes</manageDesktops>
|
||||
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||
</menu>
|
||||
|
||||
<applications>
|
||||
<!--
|
||||
# this is an example with comments through out. use these to make your
|
||||
# own rules, but without the comments of course.
|
||||
# you may use one or more of the name/class/role/title/type rules to specify
|
||||
# windows to match
|
||||
|
||||
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||
(if unspecified, then it is 'dialog' for child windows)">
|
||||
# you may set only one of name/class/role/title/type, or you may use more
|
||||
# than one together to restrict your matches.
|
||||
|
||||
# the name, class, role, and title use simple wildcard matching such as those
|
||||
# used by a shell. you can use * to match any characters and ? to match
|
||||
# any single character.
|
||||
|
||||
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||
# or desktop
|
||||
|
||||
# when multiple rules match a window, they will all be applied, in the
|
||||
# order that they appear in this list
|
||||
|
||||
|
||||
# each rule element can be left out or set to 'default' to specify to not
|
||||
# change that attribute of the window
|
||||
|
||||
<decor>yes</decor>
|
||||
# enable or disable window decorations
|
||||
|
||||
<shade>no</shade>
|
||||
# make the window shaded when it appears, or not
|
||||
|
||||
<position force="no">
|
||||
# the position is only used if both an x and y coordinate are provided
|
||||
# (and not set to 'default')
|
||||
# when force is "yes", then the window will be placed here even if it
|
||||
# says you want it placed elsewhere. this is to override buggy
|
||||
# applications who refuse to behave
|
||||
<x>center</x>
|
||||
# a number like 50, or 'center' to center on screen. use a negative number
|
||||
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||
# the right edge (or bottom). use 'default' to specify using value
|
||||
# provided by the application, or chosen by openbox, instead.
|
||||
<y>200</y>
|
||||
<monitor>1</monitor>
|
||||
# specifies the monitor in a xinerama setup.
|
||||
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||
</position>
|
||||
|
||||
<size>
|
||||
# the size to make the window.
|
||||
<width>20</width>
|
||||
# a number like 20, or 'default' to use the size given by the application.
|
||||
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||
# case the value is relative to the size of the monitor that the window
|
||||
# appears on.
|
||||
<height>30%</height>
|
||||
</size>
|
||||
|
||||
<focus>yes</focus>
|
||||
# if the window should try be given focus when it appears. if this is set
|
||||
# to yes it doesn't guarantee the window will be given focus. some
|
||||
# restrictions may apply, but Openbox will try to
|
||||
|
||||
<desktop>1</desktop>
|
||||
# 1 is the first desktop, 'all' for all desktops
|
||||
|
||||
<layer>normal</layer>
|
||||
# 'above', 'normal', or 'below'
|
||||
|
||||
<iconic>no</iconic>
|
||||
# make the window iconified when it appears, or not
|
||||
|
||||
<skip_pager>no</skip_pager>
|
||||
# asks to not be shown in pagers
|
||||
|
||||
<skip_taskbar>no</skip_taskbar>
|
||||
# asks to not be shown in taskbars. window cycling actions will also
|
||||
# skip past such windows
|
||||
|
||||
<fullscreen>yes</fullscreen>
|
||||
# make the window in fullscreen mode when it appears
|
||||
|
||||
<maximized>true</maximized>
|
||||
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||
</application>
|
||||
|
||||
# end of the example
|
||||
-->
|
||||
</applications>
|
||||
|
||||
</openbox_config>
|
||||
167
test/configs/tint2/661.tint2rc
Normal file
167
test/configs/tint2/661.tint2rc
Normal file
@@ -0,0 +1,167 @@
|
||||
#---- Generated by tint2conf 6abf ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Executor
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #ff0000 100
|
||||
border_color = #000000 0
|
||||
background_color_hover = #000000 0
|
||||
border_color_hover = #000000 0
|
||||
background_color_pressed = #000000 0
|
||||
border_color_pressed = #000000 0
|
||||
|
||||
#-------------------------------------
|
||||
# Panel
|
||||
panel_items = EF
|
||||
panel_size = 100% 30
|
||||
panel_margin = 0 0
|
||||
panel_padding = 0 0 0
|
||||
panel_background_id = -1
|
||||
wm_menu = 0
|
||||
panel_dock = 0
|
||||
panel_position = top center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0
|
||||
autohide_height = 1
|
||||
strut_policy = follow_size
|
||||
panel_window_name = tint2
|
||||
disable_transparency = 0
|
||||
mouse_effects = 0
|
||||
font_shadow = 0
|
||||
mouse_hover_icon_asb = 100 0 10
|
||||
mouse_pressed_icon_asb = 100 0 0
|
||||
|
||||
#-------------------------------------
|
||||
# Taskbar
|
||||
taskbar_mode = single_desktop
|
||||
taskbar_hide_if_empty = 0
|
||||
taskbar_padding = 0 0 0
|
||||
taskbar_background_id = -1
|
||||
taskbar_active_background_id = -1
|
||||
taskbar_name = 0
|
||||
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 = 0 0
|
||||
taskbar_name_background_id = -1
|
||||
taskbar_name_active_background_id = -1
|
||||
taskbar_name_font_color = #000000 100
|
||||
taskbar_name_active_font_color = #000000 100
|
||||
taskbar_distribute_size = 0
|
||||
taskbar_sort_order = none
|
||||
task_align = left
|
||||
|
||||
#-------------------------------------
|
||||
# Task
|
||||
task_text = 0
|
||||
task_icon = 0
|
||||
task_centered = 0
|
||||
urgent_nb_of_blink = 0
|
||||
task_maximum_size = 0 0
|
||||
task_padding = 0 0 0
|
||||
task_tooltip = 0
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = none
|
||||
mouse_scroll_down = none
|
||||
|
||||
#-------------------------------------
|
||||
# System tray (notification area)
|
||||
systray_padding = 0 0 0
|
||||
systray_background_id = -1
|
||||
systray_sort = ascending
|
||||
systray_icon_size = 0
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = primary
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
launcher_padding = 0 0 0
|
||||
launcher_background_id = -1
|
||||
launcher_icon_background_id = -1
|
||||
launcher_icon_size = 0
|
||||
launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 0
|
||||
launcher_tooltip = 0
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
time1_format =
|
||||
time2_format =
|
||||
time1_timezone =
|
||||
time2_timezone =
|
||||
clock_font_color = #000000 100
|
||||
clock_padding = 0 0
|
||||
clock_background_id = -1
|
||||
clock_tooltip =
|
||||
clock_tooltip_timezone =
|
||||
clock_lclick_command =
|
||||
clock_rclick_command =
|
||||
clock_mclick_command =
|
||||
clock_uwheel_command =
|
||||
clock_dwheel_command =
|
||||
|
||||
#-------------------------------------
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 0
|
||||
battery_low_cmd =
|
||||
battery_full_cmd =
|
||||
battery_font_color = #000000 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 0 0
|
||||
battery_background_id = -1
|
||||
battery_hide = 0
|
||||
battery_lclick_command =
|
||||
battery_rclick_command =
|
||||
battery_mclick_command =
|
||||
battery_uwheel_command =
|
||||
battery_dwheel_command =
|
||||
ac_connected_cmd =
|
||||
ac_disconnected_cmd =
|
||||
|
||||
#-------------------------------------
|
||||
# Executor 1
|
||||
execp = new
|
||||
execp_command = cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 4 | head -n 1
|
||||
execp_interval = 1
|
||||
execp_has_icon = 0
|
||||
execp_cache_icon = 1
|
||||
execp_continuous = 0
|
||||
execp_markup = 1
|
||||
execp_lclick_command =
|
||||
execp_rclick_command =
|
||||
execp_mclick_command =
|
||||
execp_uwheel_command =
|
||||
execp_dwheel_command =
|
||||
execp_font = DejaVu Sans Ultra-Light 10
|
||||
execp_font_color = #000000 100
|
||||
execp_padding = 0 0
|
||||
execp_background_id = 1
|
||||
execp_centered = 0
|
||||
execp_icon_w = 0
|
||||
execp_icon_h = 0
|
||||
|
||||
#-------------------------------------
|
||||
# Tooltip
|
||||
tooltip_show_timeout = 0
|
||||
tooltip_hide_timeout = 0
|
||||
tooltip_padding = 0 0
|
||||
tooltip_background_id = -1
|
||||
tooltip_font_color = #000000 100
|
||||
|
||||
11
test/configs/xsettingsd.conf
Normal file
11
test/configs/xsettingsd.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
Net/ThemeName "ChromeDark"
|
||||
Net/IconThemeName "elementary-xfce-dark"
|
||||
|
||||
Xft/Antialias 1
|
||||
#Xft/DPI 100352
|
||||
Xft/HintStyle "hintmedium"
|
||||
Xft/Hinting 1
|
||||
Xft/RGBA "none"
|
||||
Xft/lcdfilter "none"
|
||||
|
||||
Gtk/FontName "Liberation Sans 10"
|
||||
17
test/manual-theme-check.sh
Executable file
17
test/manual-theme-check.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo -e '\033kTerminal\033\\'
|
||||
|
||||
echo "" > ../../tint2.wiki/screenshots.md
|
||||
|
||||
for f in ../themes/*tint2rc
|
||||
do
|
||||
reset
|
||||
echo $f
|
||||
name=$(basename -s .tint2rc $f)
|
||||
( ( sleep 1 ; import -window tint2 ../../tint2.wiki/screenshots/${name}.png ; echo "Screenshot taken for ${name}!" ) &)
|
||||
../build/tint2 -c $f
|
||||
sleep 1
|
||||
echo -e "### [${name}](https://gitlab.com/o9000/tint2/blob/master/themes/$(basename $f))\n" >> ../../tint2.wiki/screenshots.md
|
||||
echo -e "\n" >> ../../tint2.wiki/screenshots.md
|
||||
done
|
||||
322
test/regression.py
Executable file
322
test/regression.py
Executable file
@@ -0,0 +1,322 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import __builtin__
|
||||
|
||||
import sys
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
display = "99"
|
||||
devnull = open(os.devnull, "r+")
|
||||
ok = ":white_check_mark:"
|
||||
warning = ":warning:"
|
||||
error = ":negative_squared_cross_mark:"
|
||||
stress_duration = 10
|
||||
repeats = 1
|
||||
|
||||
|
||||
def print(*args, **kwargs):
|
||||
if "end" not in kwargs:
|
||||
kwargs["end"] = ""
|
||||
r = __builtin__.print(*args, **kwargs)
|
||||
__builtin__.print(" ")
|
||||
else:
|
||||
r = __builtin__.print(*args, **kwargs)
|
||||
__builtin__.print("\n", end="")
|
||||
return r
|
||||
|
||||
|
||||
def run(cmd, output=False):
|
||||
return subprocess.Popen(cmd,
|
||||
stdin=devnull,
|
||||
stdout=devnull if not output else subprocess.PIPE,
|
||||
stderr=devnull if not output else subprocess.STDOUT,
|
||||
shell=isinstance(cmd, basestring),
|
||||
close_fds=True,
|
||||
preexec_fn=os.setsid)
|
||||
|
||||
|
||||
def stop(p):
|
||||
os.killpg(os.getpgid(p.pid), signal.SIGTERM)
|
||||
|
||||
|
||||
def sleep(n):
|
||||
while n > 0:
|
||||
sys.stderr.write(".")
|
||||
sys.stderr.flush()
|
||||
time.sleep(1)
|
||||
n -= 1
|
||||
|
||||
|
||||
def start_xvfb():
|
||||
stop_xvfb()
|
||||
xvfb = run(["Xvfb", ":{0}".format(display), "-screen", "0", "1280x720x24", "-nolisten", "tcp", "-dpi", "96"])
|
||||
if xvfb.poll() != None:
|
||||
raise RuntimeError("Xvfb failed to start")
|
||||
os.environ["DISPLAY"] = ":{0}".format(display)
|
||||
return xvfb
|
||||
|
||||
|
||||
def stop_xvfb():
|
||||
run("kill $(netstat -ap 2>/dev/null | grep X{0} | grep LISTENING | grep -o '[0-9]*/Xvfb' | head -n 1 | cut -d / -f 1) 1>/dev/null 2>/dev/null ".format(display)).wait()
|
||||
|
||||
|
||||
def start_xsettings():
|
||||
return run(["xsettingsd", "-c", "./configs/xsettingsd.conf"])
|
||||
|
||||
|
||||
def start_wm():
|
||||
return run(["openbox", "--replace", "--config-file", "./configs/openbox.xml"])
|
||||
|
||||
def start_compositor():
|
||||
return run(["compton", "--config", "./configs/compton.conf"])
|
||||
|
||||
|
||||
def start_stressors():
|
||||
stressors = []
|
||||
stressors.append(run(["./workspaces-stress.sh"]))
|
||||
return stressors
|
||||
|
||||
|
||||
def stop_stressors(stressors):
|
||||
for s in stressors:
|
||||
stop(s)
|
||||
|
||||
|
||||
def compute_min_med_fps(out):
|
||||
samples = []
|
||||
for line in out.split("\n"):
|
||||
if "fps = " in line:
|
||||
fps = float(line.split("fps = ", 1)[-1].split(" ")[0])
|
||||
if fps > 0:
|
||||
samples.append(fps)
|
||||
samples.sort()
|
||||
return min(samples), samples[len(samples)/2]
|
||||
|
||||
|
||||
def get_mem_usage(pid):
|
||||
value = None
|
||||
with open("/proc/{0}/status".format(pid)) as f:
|
||||
for line in f:
|
||||
if line.startswith("VmRSS:"):
|
||||
rss = line.split(":", 1)[-1].strip()
|
||||
value, multiplier = rss.split(" ")
|
||||
value = float(value)
|
||||
if multiplier == "kB":
|
||||
value *= 1024
|
||||
else:
|
||||
raise RuntimeError("Could not parse /proc/[pid]/status")
|
||||
if not value:
|
||||
raise RuntimeError("Could not parse /proc/[pid]/status")
|
||||
return value * 1.0e-6
|
||||
|
||||
|
||||
def find_asan_leaks(out):
|
||||
traces = []
|
||||
trace = None
|
||||
for line in out.split("\n"):
|
||||
line = line.strip()
|
||||
if " leak of " in line and " allocated from:" in line:
|
||||
trace = []
|
||||
if trace != None:
|
||||
if line.startswith("#"):
|
||||
trace.append(line)
|
||||
else:
|
||||
if any([ "tint2" in frame for frame in trace ]):
|
||||
traces.append(trace)
|
||||
trace = None
|
||||
return traces
|
||||
|
||||
|
||||
def test(tint2path, config):
|
||||
start_xvfb()
|
||||
sleep(1)
|
||||
start_xsettings()
|
||||
start_wm()
|
||||
sleep(1)
|
||||
os.environ["DEBUG_FPS"] = "1"
|
||||
os.environ["ASAN_OPTIONS"] = "detect_leaks=1"
|
||||
tint2 = run(["tint2", "-c", config], True)
|
||||
if tint2.poll() != None:
|
||||
raise RuntimeError("tint2 failed to start")
|
||||
sleep(1)
|
||||
# Handle late compositor start
|
||||
compton = start_compositor()
|
||||
sleep(2)
|
||||
# Stress test with compositor on
|
||||
stressors = start_stressors()
|
||||
sleep(stress_duration)
|
||||
stop_stressors(stressors)
|
||||
# Handle compositor stopping
|
||||
stop(compton)
|
||||
# Stress test with compositor off
|
||||
stressors = start_stressors()
|
||||
sleep(stress_duration)
|
||||
stop_stressors(stressors)
|
||||
# Handle WM restart
|
||||
start_wm()
|
||||
# Stress test with new WM
|
||||
stressors = start_stressors()
|
||||
sleep(stress_duration)
|
||||
stop_stressors(stressors)
|
||||
# Collect info
|
||||
mem = get_mem_usage(tint2.pid)
|
||||
stop(tint2)
|
||||
out, _ = tint2.communicate()
|
||||
exitcode = tint2.returncode
|
||||
if exitcode != 0:
|
||||
print("tint2 crashed with exit code {0}!".format(exitcode))
|
||||
print("Output:")
|
||||
print("```\n" + out.strip() + "\n```")
|
||||
return
|
||||
min_fps, med_fps = compute_min_med_fps(out)
|
||||
leaks = find_asan_leaks(out)
|
||||
sys.stderr.write("\n")
|
||||
mem_status = ok if mem < 20 else warning if mem < 40 else error
|
||||
print("Memory usage: %.1f %s %s" % (mem, "MB", mem_status))
|
||||
leak_status = ok if not leaks else error
|
||||
print("Memory leak count:", len(leaks), leak_status)
|
||||
for leak in leaks:
|
||||
print("Memory leak:")
|
||||
for line in leak:
|
||||
print(line)
|
||||
fps_status = ok if min_fps > 60 else warning if min_fps > 40 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:")
|
||||
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"))
|
||||
|
||||
|
||||
def show_git_info(src_dir):
|
||||
out, _ = run("cd {0}; git show -s '--format=[%ci] %h %s %d'".format(src_dir), True).communicate()
|
||||
print("Last commit:", out.strip())
|
||||
diff, _ = run("cd {0}; git diff".format(src_dir), True).communicate()
|
||||
diff = diff.strip()
|
||||
diff_staged, _ = run("cd {0}; git diff --staged".format(src_dir), True).communicate()
|
||||
diff_staged = diff_staged.strip()
|
||||
if diff or diff_staged:
|
||||
print("Repository not clean", warning)
|
||||
if diff:
|
||||
print("Diff:")
|
||||
print("```\n" + diff + "\n```")
|
||||
if diff_staged:
|
||||
print("Diff staged:")
|
||||
print("```\n" + diff_staged + "\n```")
|
||||
|
||||
|
||||
def show_system_info():
|
||||
out, _ = run("lsb_release -sd", True).communicate()
|
||||
out = out.strip()
|
||||
print("System:", out)
|
||||
out, _ = run("cat /proc/cpuinfo | grep 'model name' | head -n1 | cut -d ':' -f2", True).communicate()
|
||||
out = out.strip()
|
||||
print("Hardware:", out)
|
||||
out, _ = run("cc --version | head -n1", True).communicate()
|
||||
out = out.strip()
|
||||
print("Compiler:", out)
|
||||
|
||||
|
||||
def compile_and_report(src_dir):
|
||||
print("# Compilation")
|
||||
cmake_flags = "-DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON '-DCMAKE_CXX_FLAGS_DEBUG=-O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow' '-DCMAKE_EXE_LINKER_FLAGS=-O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold'"
|
||||
print("Flags:", cmake_flags)
|
||||
start = time.time()
|
||||
c = run("rm -rf build; mkdir build; cd build; cmake {0} {1} ; make -j7".format(cmake_flags, src_dir), True)
|
||||
out, _ = c.communicate()
|
||||
duration = time.time() - start
|
||||
if c.returncode != 0:
|
||||
print("Status: Failed!", error)
|
||||
print("Output:")
|
||||
print("```\n" + out.strip() + "\n```")
|
||||
raise RuntimeError("compilation failed")
|
||||
if "warning:" in out:
|
||||
print("Status: Succeeded with warnings!", warning)
|
||||
print("Warnings:")
|
||||
print("```", end="")
|
||||
for line in out.split("\n"):
|
||||
if "warning:" in line:
|
||||
print(line, end="")
|
||||
print("```", end="")
|
||||
else:
|
||||
print("Status: Succeeded in %.1f seconds" % (duration,), ok)
|
||||
|
||||
|
||||
def run_test(config, index):
|
||||
print("# Test", index)
|
||||
print("Config: [{0}]({1})".format(config.split("/")[-1].replace(".tint2rc", ""), "https://gitlab.com/o9000/tint2/blob/master/test/" + config))
|
||||
for i in range(repeats):
|
||||
test("./build/tint2", config)
|
||||
|
||||
|
||||
def run_tests():
|
||||
configs = []
|
||||
configs += ["./configs/tint2/" +s for s in os.listdir("./configs/tint2") ]
|
||||
configs += ["../themes/" + s for s in os.listdir("../themes")]
|
||||
index = 0
|
||||
for config in configs:
|
||||
index += 1
|
||||
run_test(config, index)
|
||||
print("")
|
||||
|
||||
|
||||
def get_default_src_dir():
|
||||
return os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/../")
|
||||
|
||||
|
||||
def check_busy():
|
||||
out, _ = run("top -bn5 | grep 'Cpu(s)' | grep -o '[0-9\.]* id' | cut -d ' ' -f 1", True).communicate()
|
||||
load_samples = []
|
||||
for line in out.split("\n"):
|
||||
line = line.strip()
|
||||
if line:
|
||||
load_samples.append(100. - float(line))
|
||||
load_samples.sort()
|
||||
load = load_samples[len(load_samples)/2]
|
||||
if load > 10.0:
|
||||
raise RuntimeError("The system appears busy. Load: %f.1%%." % (load,))
|
||||
|
||||
|
||||
def checkout(version):
|
||||
p = run("rm -rf tmpclone; git clone https://gitlab.com/o9000/tint2.git tmpclone; cd tmpclone; git checkout {0}".format(version), True)
|
||||
out, _ = p.communicate()
|
||||
if p.returncode != 0:
|
||||
sys.stderr.write(out)
|
||||
raise RuntimeError("git clone failed!")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--src_dir", default=get_default_src_dir())
|
||||
parser.add_argument("--for_version", default="HEAD")
|
||||
args = parser.parse_args()
|
||||
if args.for_version != "HEAD":
|
||||
checkout(args.for_version)
|
||||
args.src_dir = "./tmpclone"
|
||||
args.src_dir = os.path.realpath(args.src_dir)
|
||||
stop_xvfb()
|
||||
check_busy()
|
||||
show_timestamp()
|
||||
show_git_info(args.src_dir)
|
||||
show_system_info()
|
||||
compile_and_report(args.src_dir)
|
||||
run_tests()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), "w", 0)
|
||||
main()
|
||||
@@ -1,11 +1,14 @@
|
||||
#---- Generated by tint2conf 2e3c ----
|
||||
#---- Generated by tint2conf 08d3 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #111111 100
|
||||
border_color = #333333 100
|
||||
background_color_hover = #111111 100
|
||||
@@ -16,6 +19,7 @@ border_color_pressed = #333333 100
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #111111 100
|
||||
border_color = #222222 100
|
||||
background_color_hover = #111111 100
|
||||
@@ -26,6 +30,7 @@ border_color_pressed = #555555 100
|
||||
# Background 3: Active task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #222222 100
|
||||
border_color = #777777 100
|
||||
background_color_hover = #222222 100
|
||||
@@ -36,6 +41,7 @@ border_color_pressed = #777777 100
|
||||
# Background 4: Urgent task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
@@ -46,6 +52,7 @@ border_color_pressed = #aa7733 100
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
@@ -56,6 +63,7 @@ border_color_pressed = #999999 100
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #111111 100
|
||||
border_color = #222222 100
|
||||
background_color_hover = #111111 100
|
||||
@@ -66,6 +74,7 @@ border_color_pressed = #555555 100
|
||||
# Background 7: Active desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #222222 100
|
||||
border_color = #777777 30
|
||||
background_color_hover = #222222 100
|
||||
@@ -85,7 +94,7 @@ panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
primary_monitor_first = 0
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
@@ -101,12 +110,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 = 6 3
|
||||
taskbar_name_background_id = 6
|
||||
@@ -148,6 +159,7 @@ systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
@@ -159,12 +171,12 @@ launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = /usr/share/applications/tint2conf.desktop
|
||||
launcher_item_app = /usr/local/share/applications/tint2conf.desktop
|
||||
launcher_item_app = /usr/share/applications/firefox.desktop
|
||||
launcher_item_app = /usr/share/applications/iceweasel.desktop
|
||||
launcher_item_app = /usr/share/applications/chromium-browser.desktop
|
||||
launcher_item_app = /usr/share/applications/google-chrome.desktop
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
@@ -190,9 +202,12 @@ clock_dwheel_command =
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #eeeeee 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#---- Generated by tint2conf ab72 ----
|
||||
#---- Generated by tint2conf 3947 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #000000 80
|
||||
border_color = #555555 80
|
||||
background_color_hover = #000000 80
|
||||
@@ -16,6 +19,7 @@ border_color_pressed = #555555 80
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #777777 4
|
||||
@@ -26,6 +30,7 @@ border_color_pressed = #777777 30
|
||||
# Background 3: Active task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #555555 10
|
||||
border_color = #ffffff 60
|
||||
background_color_hover = #cccccc 10
|
||||
@@ -36,6 +41,7 @@ border_color_pressed = #ffffff 60
|
||||
# Background 4: Urgent task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
@@ -46,6 +52,7 @@ border_color_pressed = #aa7733 100
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
@@ -56,6 +63,7 @@ border_color_pressed = #999999 100
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #777777 0
|
||||
border_color = #777777 30
|
||||
background_color_hover = #777777 4
|
||||
@@ -66,6 +74,7 @@ border_color_pressed = #777777 30
|
||||
# Background 7: Active desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #555555 10
|
||||
border_color = #ffffff 60
|
||||
background_color_hover = #555555 10
|
||||
@@ -85,6 +94,7 @@ panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
@@ -100,12 +110,15 @@ 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 = 6 3
|
||||
taskbar_name_background_id = 6
|
||||
taskbar_name_active_background_id = 7
|
||||
@@ -146,6 +159,7 @@ systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
@@ -157,10 +171,12 @@ launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = /usr/share/applications/firefox.desktop
|
||||
launcher_item_app = /usr/share/applications/iceweasel.desktop
|
||||
launcher_item_app = /usr/share/applications/google-chrome.desktop
|
||||
launcher_item_app = /usr/local/share/applications/tint2conf.desktop
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
@@ -186,9 +202,12 @@ clock_dwheel_command =
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #eeeeee 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
|
||||
248
themes/horizontal-icon-only.tint2rc
Normal file
248
themes/horizontal-icon-only.tint2rc
Normal file
@@ -0,0 +1,248 @@
|
||||
#---- Generated by tint2conf 70c4 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
border_sides = TLR
|
||||
background_color = #000000 80
|
||||
border_color = #555555 80
|
||||
background_color_hover = #000000 80
|
||||
border_color_hover = #555555 80
|
||||
background_color_pressed = #000000 80
|
||||
border_color_pressed = #555555 80
|
||||
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #777777 4
|
||||
border_color_hover = #cccccc 30
|
||||
background_color_pressed = #989898 21
|
||||
border_color_pressed = #777777 30
|
||||
|
||||
# Background 3: Active task
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #ffffff 21
|
||||
border_color = #ffffff 60
|
||||
background_color_hover = #ffffff 21
|
||||
border_color_hover = #ffffff 60
|
||||
background_color_pressed = #989898 21
|
||||
border_color_pressed = #ffffff 60
|
||||
|
||||
# Background 4: Urgent task
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
border_color_hover = #aa7733 100
|
||||
background_color_pressed = #aa4400 100
|
||||
border_color_pressed = #aa7733 100
|
||||
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
border_color_hover = #999999 100
|
||||
background_color_pressed = #ffffaa 100
|
||||
border_color_pressed = #999999 100
|
||||
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #777777 0
|
||||
border_color = #777777 30
|
||||
background_color_hover = #bdbdbd 21
|
||||
border_color_hover = #cccccc 30
|
||||
background_color_pressed = #777777 21
|
||||
border_color_pressed = #777777 30
|
||||
|
||||
# Background 7: Active desktop name
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #ffffff 21
|
||||
border_color = #ffffff 60
|
||||
background_color_hover = #ffffff 21
|
||||
border_color_hover = #ffffff 60
|
||||
background_color_pressed = #a9a9a9 21
|
||||
border_color_pressed = #ffffff 60
|
||||
|
||||
#-------------------------------------
|
||||
# Panel
|
||||
panel_items = L:T:SC
|
||||
panel_size = 100% 32
|
||||
panel_margin = 0 0
|
||||
panel_padding = 4 0 4
|
||||
panel_background_id = 1
|
||||
wm_menu = 1
|
||||
panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
panel_shrink = 1
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
autohide_height = 2
|
||||
strut_policy = follow_size
|
||||
panel_window_name = tint2
|
||||
disable_transparency = 0
|
||||
mouse_effects = 1
|
||||
font_shadow = 0
|
||||
mouse_hover_icon_asb = 100 0 10
|
||||
mouse_pressed_icon_asb = 100 0 0
|
||||
|
||||
#-------------------------------------
|
||||
# Taskbar
|
||||
taskbar_mode = multi_desktop
|
||||
taskbar_hide_if_empty = 0
|
||||
taskbar_padding = 0 0 0
|
||||
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 0
|
||||
taskbar_name_background_id = 6
|
||||
taskbar_name_active_background_id = 7
|
||||
taskbar_name_font = sans bold 9
|
||||
taskbar_name_font_color = #dddddd 100
|
||||
taskbar_name_active_font_color = #dddddd 100
|
||||
taskbar_distribute_size = 1
|
||||
taskbar_sort_order = none
|
||||
task_align = left
|
||||
|
||||
#-------------------------------------
|
||||
# Task
|
||||
task_text = 0
|
||||
task_icon = 1
|
||||
task_centered = 1
|
||||
urgent_nb_of_blink = 100000
|
||||
task_maximum_size = 35 35
|
||||
task_padding = 4 3 4
|
||||
task_font = sans 8
|
||||
task_tooltip = 1
|
||||
task_font_color = #eeeeee 100
|
||||
task_icon_asb = 100 0 0
|
||||
task_background_id = 2
|
||||
task_active_background_id = 3
|
||||
task_urgent_background_id = 4
|
||||
task_iconified_background_id = 2
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = prev_task
|
||||
mouse_scroll_down = next_task
|
||||
|
||||
#-------------------------------------
|
||||
# System tray (notification area)
|
||||
systray_padding = 0 0 2
|
||||
systray_background_id = 0
|
||||
systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
launcher_padding = 0 0 2
|
||||
launcher_background_id = 0
|
||||
launcher_icon_background_id = 0
|
||||
launcher_icon_size = 22
|
||||
launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
time1_format = %H:%M
|
||||
time2_format = %A %d %B
|
||||
time1_font = sans bold 8
|
||||
time1_timezone =
|
||||
time2_timezone =
|
||||
time2_font = sans 7
|
||||
clock_font_color = #eeeeee 100
|
||||
clock_padding = 1 0
|
||||
clock_background_id = 0
|
||||
clock_tooltip =
|
||||
clock_tooltip_timezone =
|
||||
clock_lclick_command = zenity --calendar --text ""
|
||||
clock_rclick_command = orage
|
||||
clock_mclick_command =
|
||||
clock_uwheel_command =
|
||||
clock_dwheel_command =
|
||||
|
||||
#-------------------------------------
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #eeeeee 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
battery_lclick_command =
|
||||
battery_rclick_command =
|
||||
battery_mclick_command =
|
||||
battery_uwheel_command =
|
||||
battery_dwheel_command =
|
||||
ac_connected_cmd =
|
||||
ac_disconnected_cmd =
|
||||
|
||||
#-------------------------------------
|
||||
# Separator 1
|
||||
separator = new
|
||||
separator_background_id = 0
|
||||
separator_color = #777777 85
|
||||
separator_style = dots
|
||||
separator_size = 3
|
||||
separator_padding = 1 0
|
||||
|
||||
#-------------------------------------
|
||||
# Separator 2
|
||||
separator = new
|
||||
separator_background_id = 0
|
||||
separator_color = #777777 85
|
||||
separator_style = dots
|
||||
separator_size = 3
|
||||
separator_padding = 1 0
|
||||
|
||||
#-------------------------------------
|
||||
# Tooltip
|
||||
tooltip_show_timeout = 0.5
|
||||
tooltip_hide_timeout = 0.1
|
||||
tooltip_padding = 2 2
|
||||
tooltip_background_id = 5
|
||||
tooltip_font_color = #222222 100
|
||||
tooltip_font = sans 9
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#---- Generated by tint2conf 079a ----
|
||||
#---- Generated by tint2conf f101 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 100
|
||||
border_color = #bbbbbb 100
|
||||
background_color_hover = #eeeeee 100
|
||||
@@ -16,6 +19,7 @@ border_color_pressed = #bbbbbb 100
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 100
|
||||
border_color = #eeeeee 100
|
||||
background_color_hover = #eeeeee 100
|
||||
@@ -26,6 +30,7 @@ border_color_pressed = #cccccc 100
|
||||
# Background 3: Active task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #dddddd 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #eeeeee 100
|
||||
@@ -36,6 +41,7 @@ border_color_pressed = #999999 100
|
||||
# Background 4: Urgent task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
@@ -46,6 +52,7 @@ border_color_pressed = #aa7733 100
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
@@ -56,6 +63,7 @@ border_color_pressed = #999999 100
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 100
|
||||
border_color = #cccccc 100
|
||||
background_color_hover = #eeeeee 100
|
||||
@@ -66,6 +74,7 @@ border_color_pressed = #cccccc 100
|
||||
# Background 7: Active desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #dddddd 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #dddddd 100
|
||||
@@ -76,6 +85,7 @@ border_color_pressed = #999999 100
|
||||
# Background 8: Systray
|
||||
rounded = 3
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #dddddd 100
|
||||
border_color = #cccccc 100
|
||||
background_color_hover = #dddddd 100
|
||||
@@ -95,6 +105,7 @@ panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
@@ -110,12 +121,15 @@ 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 = 6 3
|
||||
taskbar_name_background_id = 6
|
||||
taskbar_name_active_background_id = 7
|
||||
@@ -156,6 +170,7 @@ systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
@@ -167,8 +182,12 @@ launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = /usr/share/applications/firefox.desktop
|
||||
launcher_item_app = /usr/share/applications/iceweasel.desktop
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
@@ -194,9 +213,12 @@ clock_dwheel_command =
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #222222 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#---- Generated by tint2conf 2c73 ----
|
||||
#---- Generated by tint2conf 6ae3 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 0
|
||||
border_color = #bbbbbb 10
|
||||
background_color_hover = #eeeeee 0
|
||||
@@ -16,6 +19,7 @@ border_color_pressed = #bbbbbb 10
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 4
|
||||
border_color = #cccccc 44
|
||||
background_color_hover = #eeeeee 22
|
||||
@@ -26,6 +30,7 @@ border_color_pressed = #eaeaea 44
|
||||
# Background 3: Active task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #dddddd 4
|
||||
border_color = #999999 100
|
||||
background_color_hover = #eeeeee 22
|
||||
@@ -36,6 +41,7 @@ border_color_pressed = #999999 100
|
||||
# Background 4: Urgent task
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
@@ -46,6 +52,7 @@ border_color_pressed = #aa7733 100
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
@@ -56,6 +63,7 @@ border_color_pressed = #999999 100
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #eeeeee 4
|
||||
border_color = #cccccc 30
|
||||
background_color_hover = #eeeeee 22
|
||||
@@ -66,6 +74,7 @@ border_color_pressed = #999999 30
|
||||
# Background 7: Active desktop name
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #dddddd 3
|
||||
border_color = #999999 100
|
||||
background_color_hover = #dddddd 3
|
||||
@@ -85,7 +94,7 @@ panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
primary_monitor_first = 0
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
@@ -101,12 +110,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 = 6 3
|
||||
taskbar_name_background_id = 6
|
||||
@@ -148,6 +159,7 @@ systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
@@ -159,12 +171,12 @@ launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = /usr/share/applications/tint2conf.desktop
|
||||
launcher_item_app = /usr/local/share/applications/tint2conf.desktop
|
||||
launcher_item_app = /usr/share/applications/firefox.desktop
|
||||
launcher_item_app = /usr/share/applications/iceweasel.desktop
|
||||
launcher_item_app = /usr/share/applications/chromium-browser.desktop
|
||||
launcher_item_app = /usr/share/applications/google-chrome.desktop
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
@@ -190,9 +202,12 @@ clock_dwheel_command =
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #ffffff 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
|
||||
238
themes/horizontal-text-only.tint2rc
Normal file
238
themes/horizontal-text-only.tint2rc
Normal file
@@ -0,0 +1,238 @@
|
||||
#---- Generated by tint2conf 20b6 ----
|
||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
# Gradient 1
|
||||
gradient = vertical
|
||||
start_color = #2d2d2d 80
|
||||
end_color = #000000 80
|
||||
color_stop = 70.000000 #1c1c1c 80
|
||||
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
border_sides = T
|
||||
background_color = #000000 80
|
||||
border_color = #333333 80
|
||||
gradient_id = 1
|
||||
background_color_hover = #000000 80
|
||||
border_color_hover = #555555 80
|
||||
background_color_pressed = #000000 80
|
||||
border_color_pressed = #555555 80
|
||||
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #777777 21
|
||||
border_color_hover = #cccccc 30
|
||||
background_color_pressed = #5a5a5a 21
|
||||
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
|
||||
|
||||
# Background 4: Urgent task
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
border_color_hover = #aa7733 100
|
||||
background_color_pressed = #aa4400 100
|
||||
border_color_pressed = #aa7733 100
|
||||
|
||||
# Background 5: Tooltip
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
border_color_hover = #999999 100
|
||||
background_color_pressed = #ffffaa 100
|
||||
border_color_pressed = #999999 100
|
||||
|
||||
# Background 6: Inactive desktop name
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #bdbdbd 21
|
||||
border_color_hover = #cccccc 100
|
||||
background_color_pressed = #777777 21
|
||||
border_color_pressed = #777777 100
|
||||
|
||||
# Background 7: Active desktop name
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
background_color = #ffffff 21
|
||||
border_color = #4c73ff 100
|
||||
background_color_hover = #ffffff 21
|
||||
border_color_hover = #4d73ff 100
|
||||
background_color_pressed = #a9a9a9 21
|
||||
border_color_pressed = #4d73ff 100
|
||||
|
||||
#-------------------------------------
|
||||
# Panel
|
||||
panel_items = LTSC
|
||||
panel_size = 100% 32
|
||||
panel_margin = 0 0
|
||||
panel_padding = 4 0 4
|
||||
panel_background_id = 1
|
||||
wm_menu = 1
|
||||
panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = normal
|
||||
panel_monitor = all
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
autohide_height = 2
|
||||
strut_policy = follow_size
|
||||
panel_window_name = tint2
|
||||
disable_transparency = 0
|
||||
mouse_effects = 1
|
||||
font_shadow = 0
|
||||
mouse_hover_icon_asb = 100 0 10
|
||||
mouse_pressed_icon_asb = 100 0 0
|
||||
|
||||
#-------------------------------------
|
||||
# Taskbar
|
||||
taskbar_mode = multi_desktop
|
||||
taskbar_hide_if_empty = 0
|
||||
taskbar_padding = 0 0 0
|
||||
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 0
|
||||
taskbar_name_background_id = 6
|
||||
taskbar_name_active_background_id = 7
|
||||
taskbar_name_font = sans bold 9
|
||||
taskbar_name_font_color = #dddddd 100
|
||||
taskbar_name_active_font_color = #dddddd 100
|
||||
taskbar_distribute_size = 1
|
||||
taskbar_sort_order = none
|
||||
task_align = left
|
||||
|
||||
#-------------------------------------
|
||||
# Task
|
||||
task_text = 1
|
||||
task_icon = 0
|
||||
task_centered = 1
|
||||
urgent_nb_of_blink = 100000
|
||||
task_maximum_size = 120 35
|
||||
task_padding = 4 3 4
|
||||
task_font = Sans 8
|
||||
task_tooltip = 1
|
||||
task_font_color = #c6c6c6 100
|
||||
task_active_font_color = #ffffff 100
|
||||
task_icon_asb = 100 0 0
|
||||
task_background_id = 2
|
||||
task_active_background_id = 3
|
||||
task_urgent_background_id = 4
|
||||
task_iconified_background_id = 2
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = prev_task
|
||||
mouse_scroll_down = next_task
|
||||
|
||||
#-------------------------------------
|
||||
# System tray (notification area)
|
||||
systray_padding = 0 0 2
|
||||
systray_background_id = 0
|
||||
systray_sort = ascending
|
||||
systray_icon_size = 22
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
launcher_padding = 0 0 2
|
||||
launcher_background_id = 0
|
||||
launcher_icon_background_id = 0
|
||||
launcher_icon_size = 22
|
||||
launcher_icon_asb = 100 0 0
|
||||
launcher_icon_theme_override = 0
|
||||
startup_notifications = 1
|
||||
launcher_tooltip = 1
|
||||
launcher_item_app = tint2conf.desktop
|
||||
launcher_item_app = firefox.desktop
|
||||
launcher_item_app = iceweasel.desktop
|
||||
launcher_item_app = chromium-browser.desktop
|
||||
launcher_item_app = google-chrome.desktop
|
||||
launcher_item_app = x-terminal-emulator.desktop
|
||||
|
||||
#-------------------------------------
|
||||
# Clock
|
||||
time1_format = %H:%M
|
||||
time2_format = %A %d %B
|
||||
time1_font = sans bold 8
|
||||
time1_timezone =
|
||||
time2_timezone =
|
||||
time2_font = sans 7
|
||||
clock_font_color = #eeeeee 100
|
||||
clock_padding = 1 0
|
||||
clock_background_id = 0
|
||||
clock_tooltip =
|
||||
clock_tooltip_timezone =
|
||||
clock_lclick_command = zenity --calendar --text ""
|
||||
clock_rclick_command = orage
|
||||
clock_mclick_command =
|
||||
clock_uwheel_command =
|
||||
clock_dwheel_command =
|
||||
|
||||
#-------------------------------------
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #eeeeee 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
battery_lclick_command =
|
||||
battery_rclick_command =
|
||||
battery_mclick_command =
|
||||
battery_uwheel_command =
|
||||
battery_dwheel_command =
|
||||
ac_connected_cmd =
|
||||
ac_disconnected_cmd =
|
||||
|
||||
#-------------------------------------
|
||||
# Tooltip
|
||||
tooltip_show_timeout = 0.5
|
||||
tooltip_hide_timeout = 0.1
|
||||
tooltip_padding = 2 2
|
||||
tooltip_background_id = 5
|
||||
tooltip_font_color = #222222 100
|
||||
tooltip_font = sans 9
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
# Tint2 config file
|
||||
# Generated by tintwizard (http://code.google.com/p/tintwizard/)
|
||||
# For information on manually configuring tint2 see http://code.google.com/p/tint2/wiki/Configure
|
||||
|
||||
# Background definitions
|
||||
# ID 1
|
||||
rounded = 7
|
||||
border_width = 2
|
||||
background_color = #000000 60
|
||||
border_color = #FFFFFF 17
|
||||
|
||||
# ID 2
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #FFFFFF 40
|
||||
border_color = #FFFFFF 49
|
||||
|
||||
# ID 3
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #FFFFFF 17
|
||||
border_color = #FFFFFF 69
|
||||
|
||||
# Panel
|
||||
panel_monitor = all
|
||||
panel_position = bottom center horizontal
|
||||
panel_size = 94% 30
|
||||
panel_margin = 0 0
|
||||
panel_padding = 7 0 7
|
||||
panel_dock = 0
|
||||
wm_menu = 0
|
||||
panel_layer = top
|
||||
panel_background_id = 1
|
||||
|
||||
# Panel Autohide
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0.3
|
||||
autohide_hide_timeout = 2
|
||||
autohide_height = 2
|
||||
strut_policy = follow_size
|
||||
|
||||
# Taskbar
|
||||
taskbar_mode = single_desktop
|
||||
taskbar_padding = 2 3 2
|
||||
taskbar_background_id = 0
|
||||
taskbar_active_background_id = 0
|
||||
|
||||
# Tasks
|
||||
urgent_nb_of_blink = 8
|
||||
task_icon = 1
|
||||
task_text = 1
|
||||
task_centered = 1
|
||||
task_maximum_size = 140 35
|
||||
task_padding = 6 2
|
||||
task_background_id = 3
|
||||
task_active_background_id = 2
|
||||
task_urgent_background_id = 2
|
||||
task_iconified_background_id = 3
|
||||
task_tooltip = 0
|
||||
|
||||
# Task Icons
|
||||
task_icon_asb = 70 0 0
|
||||
task_active_icon_asb = 100 0 0
|
||||
task_urgent_icon_asb = 100 0 0
|
||||
task_iconified_icon_asb = 70 0 0
|
||||
|
||||
# Fonts
|
||||
task_font = sans 7
|
||||
task_font_color = #FFFFFF 69
|
||||
task_active_font_color = #FFFFFF 84
|
||||
task_urgent_font_color = #FFFFFF 84
|
||||
task_iconified_font_color = #FFFFFF 69
|
||||
font_shadow = 0
|
||||
|
||||
# System Tray
|
||||
systray = 1
|
||||
systray_padding = 0 4 5
|
||||
systray_sort = ascending
|
||||
systray_background_id = 0
|
||||
systray_icon_size = 16
|
||||
systray_icon_asb = 70 0 0
|
||||
|
||||
# Clock
|
||||
time1_format = %H:%M
|
||||
time1_font = sans 8
|
||||
time2_format = %A %d %B
|
||||
time2_font = sans 6
|
||||
clock_font_color = #FFFFFF 75
|
||||
clock_padding = 1 0
|
||||
clock_background_id = 0
|
||||
clock_rclick_command = orage
|
||||
|
||||
# Tooltips
|
||||
tooltip_padding = 2 2
|
||||
tooltip_show_timeout = 0.7
|
||||
tooltip_hide_timeout = 0.3
|
||||
tooltip_background_id = 1
|
||||
tooltip_font = sans 10
|
||||
tooltip_font_color = #000000 80
|
||||
|
||||
# Mouse
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = toggle
|
||||
mouse_scroll_down = iconify
|
||||
|
||||
# Battery
|
||||
battery = 0
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_hide = 98
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #FFFFFF 75
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
|
||||
# End of config
|
||||
@@ -1,118 +0,0 @@
|
||||
# Tint2 config file
|
||||
# Generated by tintwizard (http://code.google.com/p/tintwizard/)
|
||||
# For information on manually configuring tint2 see http://code.google.com/p/tint2/wiki/Configure
|
||||
|
||||
# Background definitions
|
||||
# ID 1
|
||||
rounded = 7
|
||||
border_width = 1
|
||||
background_color = #000000 60
|
||||
border_color = #FFFFFF 17
|
||||
|
||||
# ID 2
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #FFFFFF 40
|
||||
border_color = #FFFFFF 49
|
||||
|
||||
# ID 3
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #FFFFFF 17
|
||||
border_color = #FFFFFF 69
|
||||
|
||||
# Panel
|
||||
panel_monitor = all
|
||||
panel_position = bottom center horizontal
|
||||
panel_size = 98% 28
|
||||
panel_margin = 0 5
|
||||
panel_padding = 3 0 3
|
||||
panel_dock = 0
|
||||
wm_menu = 0
|
||||
panel_layer = bottom
|
||||
panel_background_id = 0
|
||||
|
||||
# Panel Autohide
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0.7
|
||||
autohide_hide_timeout = 1.5
|
||||
autohide_height = 2
|
||||
strut_policy = follow_size
|
||||
|
||||
# Taskbar
|
||||
taskbar_mode = single_desktop
|
||||
taskbar_padding = 2 2 2
|
||||
taskbar_background_id = 1
|
||||
taskbar_active_background_id = 1
|
||||
|
||||
# Tasks
|
||||
urgent_nb_of_blink = 8
|
||||
task_icon = 1
|
||||
task_text = 1
|
||||
task_centered = 1
|
||||
task_maximum_size = 140 35
|
||||
task_padding = 2 3
|
||||
task_background_id = 3
|
||||
task_active_background_id = 2
|
||||
task_urgent_background_id = 2
|
||||
task_iconified_background_id = 3
|
||||
task_tooltip = 0
|
||||
|
||||
# Task Icons
|
||||
task_icon_asb = 80 0 0
|
||||
task_active_icon_asb = 100 0 0
|
||||
task_urgent_icon_asb = 100 0 0
|
||||
task_iconified_icon_asb = 80 0 0
|
||||
|
||||
# Fonts
|
||||
task_font = Sawasdee Bold 8
|
||||
task_font_color = #FFFFFF 89
|
||||
task_active_font_color = #FFFFFF 100
|
||||
task_urgent_font_color = #FFFFFF 100
|
||||
task_iconified_font_color = #FFFFFF 89
|
||||
font_shadow = 0
|
||||
|
||||
# System Tray
|
||||
systray = 1
|
||||
systray_padding = 6 0 5
|
||||
systray_sort = left2right
|
||||
systray_background_id = 1
|
||||
systray_icon_size = 18
|
||||
systray_icon_asb = 100 0 -10
|
||||
|
||||
# Clock
|
||||
time1_format = %H:%M
|
||||
time1_font = Sawasdee Bold 12
|
||||
clock_font_color = #FFFFFF 89
|
||||
clock_tooltip = %A %d %B
|
||||
clock_padding = 4 0
|
||||
clock_background_id = 1
|
||||
clock_rclick_command = gsimplecal
|
||||
|
||||
# Tooltips
|
||||
tooltip_padding = 5 0
|
||||
tooltip_show_timeout = 0.7
|
||||
tooltip_hide_timeout = 0.3
|
||||
tooltip_background_id = 1
|
||||
tooltip_font = Sans 10
|
||||
tooltip_font_color = #000000 80
|
||||
|
||||
# Mouse
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = close
|
||||
mouse_right = none
|
||||
mouse_scroll_up = toggle
|
||||
mouse_scroll_down = iconify
|
||||
|
||||
# Battery
|
||||
battery = 0
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_hide = 95
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #FFFFFF 75
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
|
||||
# End of config
|
||||
@@ -1,124 +0,0 @@
|
||||
# Tint2 config file
|
||||
# Generated by tintwizard (http://code.google.com/p/tintwizard/)
|
||||
# For information on manually configuring tint2 see http://code.google.com/p/tint2/wiki/Configure
|
||||
|
||||
# Background definitions
|
||||
# ID 1
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
background_color = #EAEAEA 100
|
||||
border_color = #BBBBBB 100
|
||||
|
||||
# ID 2
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
background_color = #E0EBE7 100
|
||||
border_color = #BBBBBB 100
|
||||
|
||||
# ID 3
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
background_color = #FCFAFB 100
|
||||
border_color = #BBBBBB 100
|
||||
|
||||
# ID 4
|
||||
rounded = 2
|
||||
border_width = 2
|
||||
background_color = #E0EBE7 100
|
||||
border_color = #F15A7D 80
|
||||
|
||||
# Panel
|
||||
panel_monitor = all
|
||||
panel_position = bottom center horizontal
|
||||
panel_size = 100% 30
|
||||
panel_margin = 0 0
|
||||
panel_padding = 7 3 4
|
||||
panel_dock = 0
|
||||
wm_menu = 1
|
||||
panel_layer = top
|
||||
panel_background_id = 1
|
||||
|
||||
# Panel Autohide
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0.7
|
||||
autohide_hide_timeout = 1.5
|
||||
autohide_height = 2
|
||||
strut_policy = follow_size
|
||||
|
||||
# Taskbar
|
||||
taskbar_mode = single_desktop
|
||||
taskbar_padding = 0 0 2
|
||||
taskbar_background_id = 0
|
||||
#taskbar_active_background_id = 0
|
||||
|
||||
# Tasks
|
||||
urgent_nb_of_blink = 20
|
||||
task_icon = 1
|
||||
task_text = 1
|
||||
task_centered = 1
|
||||
task_maximum_size = 140 40
|
||||
task_padding = 5 3
|
||||
task_background_id = 2
|
||||
task_active_background_id = 3
|
||||
task_urgent_background_id = 4
|
||||
task_iconified_background_id = 2
|
||||
task_tooltip = 1
|
||||
|
||||
# Task Icons
|
||||
task_icon_asb = 80 0 0
|
||||
task_active_icon_asb = 100 0 0
|
||||
task_urgent_icon_asb = 100 0 0
|
||||
task_iconified_icon_asb = 80 0 0
|
||||
|
||||
# Fonts
|
||||
task_font = sans 10
|
||||
task_font_color = #000000 100
|
||||
task_active_font_color = #000000 100
|
||||
task_urgent_font_color = #000000 100
|
||||
task_iconified_font_color = #000000 100
|
||||
font_shadow = 0
|
||||
|
||||
# System Tray
|
||||
systray = 1
|
||||
systray_padding = 5 0 5
|
||||
systray_sort = ascending
|
||||
systray_background_id = 2
|
||||
systray_icon_size = 15
|
||||
systray_icon_asb = 100 0 -10
|
||||
|
||||
# Clock
|
||||
time1_format = %F %l:%M %P
|
||||
time1_font = sans 10
|
||||
clock_font_color = #000000 100
|
||||
clock_tooltip = %A %d %B
|
||||
clock_padding = 1 1
|
||||
clock_background_id = 0
|
||||
clock_rclick_command = gsimplecal
|
||||
|
||||
# Tooltips
|
||||
tooltip_padding = 5 0
|
||||
tooltip_show_timeout = 1.2
|
||||
tooltip_hide_timeout = 0.3
|
||||
tooltip_background_id = 1
|
||||
tooltip_font = Sans 9
|
||||
tooltip_font_color = #5E5E5E 100
|
||||
|
||||
# Mouse
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = toggle
|
||||
mouse_scroll_down = iconify
|
||||
|
||||
# Battery
|
||||
battery = 0
|
||||
battery_low_status = 20
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_hide = 95
|
||||
bat1_font = Sans 9
|
||||
bat2_font = Sans 8
|
||||
battery_font_color = #000000 100
|
||||
battery_padding = 1 1
|
||||
battery_background_id = 0
|
||||
|
||||
# End of config
|
||||
@@ -1,124 +0,0 @@
|
||||
# Tint2 config file
|
||||
# Generated by tintwizard (http://code.google.com/p/tintwizard/)
|
||||
# For information on manually configuring tint2 see http://code.google.com/p/tint2/wiki/Configure
|
||||
|
||||
# Background definitions
|
||||
# ID 1
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #000000 60
|
||||
border_color = #FFFFFF 20
|
||||
|
||||
# ID 2
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
background_color = #FFFFFF 0
|
||||
border_color = #FFFFFF 20
|
||||
|
||||
# ID 3
|
||||
rounded = 5
|
||||
border_width = 0
|
||||
background_color = #000000 29
|
||||
border_color = #000000 0
|
||||
|
||||
# ID 4
|
||||
rounded = 5
|
||||
border_width = 1
|
||||
background_color = #E80000 60
|
||||
border_color = #FFFFFF 20
|
||||
|
||||
# Panel
|
||||
panel_monitor = all
|
||||
panel_position = bottom center horizontal
|
||||
panel_size = 92% 28
|
||||
panel_margin = 0 0
|
||||
panel_padding = 7 0 7
|
||||
panel_dock = 0
|
||||
wm_menu = 1
|
||||
panel_layer = top
|
||||
panel_background_id = 0
|
||||
|
||||
# Panel Autohide
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0.0
|
||||
autohide_hide_timeout = 0.0
|
||||
autohide_height = 0
|
||||
strut_policy = follow_size
|
||||
|
||||
# Taskbar
|
||||
taskbar_mode = multi_desktop
|
||||
taskbar_padding = 2 3 2
|
||||
taskbar_background_id = 3
|
||||
#taskbar_active_background_id = 0
|
||||
|
||||
# Tasks
|
||||
urgent_nb_of_blink = 18
|
||||
task_icon = 1
|
||||
task_text = 1
|
||||
task_centered = 1
|
||||
task_maximum_size = 140 30
|
||||
task_padding = 2 3
|
||||
task_background_id = 2
|
||||
task_active_background_id = 1
|
||||
task_urgent_background_id = 4
|
||||
task_iconified_background_id = 2
|
||||
task_tooltip = 0
|
||||
|
||||
# Task Icons
|
||||
task_icon_asb = 100 0 0
|
||||
task_active_icon_asb = 100 0 0
|
||||
task_urgent_icon_asb = 100 0 0
|
||||
task_iconified_icon_asb = 100 0 0
|
||||
|
||||
# Fonts
|
||||
task_font = sans 7
|
||||
task_font_color = #FFFFFF 69
|
||||
task_active_font_color = #FFFFFF 84
|
||||
task_urgent_font_color = #FFFFFF 84
|
||||
task_iconified_font_color = #FFFFFF 69
|
||||
font_shadow = 0
|
||||
|
||||
# System Tray
|
||||
systray = 1
|
||||
systray_padding = 5 2 5
|
||||
systray_sort = ascending
|
||||
systray_background_id = 1
|
||||
systray_icon_size = 16
|
||||
systray_icon_asb = 100 -10 -5
|
||||
|
||||
# Clock
|
||||
time1_format = %H:%M
|
||||
time1_font = sans 8
|
||||
time2_format = %A %d %B
|
||||
time2_font = sans 6
|
||||
clock_font_color = #FFFFFF 75
|
||||
clock_padding = 4 4
|
||||
clock_background_id = 1
|
||||
|
||||
# Tooltips
|
||||
tooltip_padding = 0 0
|
||||
tooltip_show_timeout = 0
|
||||
tooltip_hide_timeout = 0
|
||||
tooltip_background_id = 0
|
||||
tooltip_font = Sans 12
|
||||
tooltip_font_color = #FFFFFF 100
|
||||
|
||||
# Mouse
|
||||
mouse_left = toggle_iconify
|
||||
mouse_middle = none
|
||||
mouse_right = close
|
||||
mouse_scroll_up = toggle
|
||||
mouse_scroll_down = iconify
|
||||
|
||||
# Battery
|
||||
battery = 0
|
||||
battery_low_status = 7
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_hide = 95
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
battery_font_color = #FFFFFF 75
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 1
|
||||
|
||||
# End of config
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user