Compare commits

..

15 Commits

Author SHA1 Message Date
76751355e0 Update src/systray/systraybar.c
https://pastebin.com/UxDTv4ML
2026-05-06 21:43:03 +00:00
Chris Lee
f3aa2ef0c6 freeze code 2022-01-31 18:01:29 +00:00
Chris Lee
60734e0151 changelog for new feature 2021-12-12 02:38:23 +01:00
Chris
646dc4cb46 Merge branch 'refresh-execp-more' into 'master'
Completed refresh-execp

See merge request o9000/tint2!46
2021-12-12 01:29:15 +00:00
Arash Rohani
57dff2aad3 Completed refresh-execp 2021-12-12 01:29:15 +00:00
Chris Lee
f8f9c18cef Release 17.0.2 2021-12-04 10:46:45 +01:00
Chris Lee
56bccf2b4f Update changelog 2021-12-04 10:45:36 +01:00
Chris Lee
ec4eccd769 Add tint2-send to cmake 2021-11-21 01:23:39 +01:00
Chris Lee
2ed026ba32 Attempt to fix get window monitor 2021-11-14 10:24:14 +01:00
Chris
a4996c84bd Update .gitlab-ci.yml file 2021-06-27 23:47:21 +00:00
Chris Lee
7b42055a20 add ci pipeline 2021-06-28 01:25:46 +02:00
Chris Lee
f628cba966 Release 17.0.1 2021-05-29 11:24:56 +02:00
Chris Lee
a922884485 update changelog 2021-05-01 19:16:51 +02:00
Chris Lee
66a6238014 fix crash in single-monitor execp 2021-05-01 19:15:38 +02:00
Chris Lee
5e8c65b87e remove useless fsync 2021-05-01 19:12:28 +02:00
32 changed files with 3976 additions and 3733 deletions

34
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,34 @@
stages:
- build
- test
- release
variables:
DEBIAN_FRONTEND: 'noninteractive'
job-build:
stage: build
image: ubuntu:rolling
script:
- sed -Ei 's/^# deb-src /deb-src /' /etc/apt/sources.list
- apt-get update
- apt-get build-dep -y tint2
- apt-get install -y libgtk-3-dev git
- git clean -ffdx
- mkdir build
- cd build
- cmake ..
- make -j
job-release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG =~ /^v.*/
script:
- echo 'running release_job'
release:
name: 'Release $CI_COMMIT_TAG'
description: 'Release $CI_COMMIT_TAG / $CI_COMMIT_SHA'
tag_name: '$CI_COMMIT_TAG'
ref: '$CI_COMMIT_SHA'

View File

@@ -35,6 +35,7 @@ Contributors:
heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color
Fabian Carlström : taskbar sort order by app name Fabian Carlström : taskbar sort order by app name
Chris Billington (https://gitlab.com/chrisjbillington) : panel struts pivoting Chris Billington (https://gitlab.com/chrisjbillington) : panel struts pivoting
Arash Rohani <rohani.arash@pm.me> : helped with execp refresh
Translations: Translations:
Bosnian: Bosnian:

View File

@@ -286,7 +286,11 @@ add_dependencies( tint2 version )
set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=${CSTD} ${ASAN_C_FLAGS} ${TRACING_C_FLAGS}" ) set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=${CSTD} ${ASAN_C_FLAGS} ${TRACING_C_FLAGS}" )
set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS} ${TRACING_L_FLAGS}" ) set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS} ${TRACING_L_FLAGS}" )
add_executable(tint2-send src/tint2-send/tint2-send.c)
target_link_libraries(tint2-send ${X11_LIBRARIES})
install( TARGETS tint2 DESTINATION bin ) install( TARGETS tint2 DESTINATION bin )
install( TARGETS tint2-send DESTINATION bin )
install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps ) install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps )
install( FILES tint2.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications ) install( FILES tint2.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications )
install( FILES themes/tint2rc DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/xdg/tint2 ) install( FILES themes/tint2rc DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/xdg/tint2 )

View File

@@ -1,3 +1,12 @@
2021-12-11 master
- Enhancements:
- Added command to refresh executors (issue #747)
2021-12-04 17.0.2
- Fixes:
- On dual monitor, when minimizing Chrome window it minimizes on the wrong monitor panel (issue #818)
2021-05-29 17.0.1
- Fixes:
- Crash on panel cleanup in single-monitor execp (issue #801)
2021-04-18 17.0 2021-04-18 17.0
- Fixes: - Fixes:
- Crash when a window icon is large (issue #786) (santouits) - Crash when a window icon is large (issue #786) (santouits)

View File

@@ -1,5 +1,9 @@
# Latest stable release: 17.0 # Latest stable release: 17.0.2
Changes: https://gitlab.com/o9000/tint2/blob/17.0/ChangeLog
The final release of tint2 is 17.0.2.
The code is frozen and no more feature requests are accepted.
Changes: https://gitlab.com/o9000/tint2/blob/17.0.2/ChangeLog
Documentation: [doc/tint2.md](doc/tint2.md) Documentation: [doc/tint2.md](doc/tint2.md)
@@ -8,7 +12,7 @@ Compile it with (after you install the [dependencies](https://gitlab.com/o9000/t
``` ```
git clone https://gitlab.com/o9000/tint2.git git clone https://gitlab.com/o9000/tint2.git
cd tint2 cd tint2
git checkout 17.0 git checkout 17.0.2
mkdir build mkdir build
cd build cd build
cmake .. cmake ..

View File

@@ -595,6 +595,7 @@ panel_size = 94% 30
<h3 id="executor">Executor<a name="executor" href="#executor" class="md2man-permalink" title="permalink"></a></h3> <h3 id="executor">Executor<a name="executor" href="#executor" class="md2man-permalink" title="permalink"></a></h3>
<ul> <ul>
<li><p><code>execp = new</code> : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple <code>E</code>s in <code>panel_items</code>. <em>(since 0.12.4)</em></p></li> <li><p><code>execp = new</code> : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple <code>E</code>s in <code>panel_items</code>. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_name = text</code> : A name that can be used with <code>tint2-send refresh-execp</code> to re-execute the command.</p></li>
<li><p><code>execp_command = text</code> : Command to execute. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_command = text</code> : Command to execute. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_interval = integer</code> : The command is executed again after <code>execp_interval</code> seconds from the moment it exits. If zero, the command is executed only once. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_interval = integer</code> : The command is executed again after <code>execp_interval</code> seconds from the moment it exits. If zero, the command is executed only once. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_continuous = integer</code> : If non-zero, the last <code>execp_continuous</code> lines from the output of the command are displayed, every <code>execp_continuous</code> lines; this is useful for showing the output of commands that run indefinitely, such as <code>ping 127.0.0.1</code>. If zero, the output of the command is displayed after it finishes executing. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_continuous = integer</code> : If non-zero, the last <code>execp_continuous</code> lines from the output of the command are displayed, every <code>execp_continuous</code> lines; this is useful for showing the output of commands that run indefinitely, such as <code>ping 127.0.0.1</code>. If zero, the output of the command is displayed after it finishes executing. <em>(since 0.12.4)</em></p></li>

View File

@@ -199,9 +199,9 @@ pre {
</style> </style>
</head> </head>
<body> <body>
<h1 id="latest-stable-release-17-0"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">17.0</span><a name="latest-stable-release-17-0" href="#latest-stable-release-17-0" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/17.0/ChangeLog">https://gitlab.com/o9000/tint2/blob/17.0/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><div class="highlight"><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git <h1 id="latest-stable-release-17-0-2"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">17.0.2</span><a name="latest-stable-release-17-0-2" href="#latest-stable-release-17-0-2" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/17.0.2/ChangeLog">https://gitlab.com/o9000/tint2/blob/17.0.2/ChangeLog</a></p><p>Documentation: <a href="manual.html">manual.html</a></p><p>Compile it with (after you install the <a href="https://gitlab.com/o9000/tint2/wikis/Install#dependencies">dependencies</a>):</p><div class="highlight"><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git
cd tint2 cd tint2
git checkout 17.0 git checkout 17.0.2
mkdir build mkdir build
cd build cd build
cmake .. cmake ..

View File

@@ -1,4 +1,4 @@
.TH TINT2 1 "2021\-04\-18" 17.0 .TH TINT2 1 "2021\-12\-04" 17.0.2
.SH NAME .SH NAME
.PP .PP
tint2 \- lightweight panel/taskbar tint2 \- lightweight panel/taskbar
@@ -720,6 +720,8 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
.IP \(bu 2 .IP \(bu 2
\fB\fCexecp = new\fR : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple \fB\fCE\fRs in \fB\fCpanel_items\fR\&. \fI(since 0.12.4)\fP \fB\fCexecp = new\fR : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple \fB\fCE\fRs in \fB\fCpanel_items\fR\&. \fI(since 0.12.4)\fP
.IP \(bu 2 .IP \(bu 2
\fB\fCexecp_name = text\fR : A name that can be used with \fB\fCtint2\-send refresh\-execp\fR to re\-execute the command.
.IP \(bu 2
\fB\fCexecp_command = text\fR : Command to execute. \fI(since 0.12.4)\fP \fB\fCexecp_command = text\fR : Command to execute. \fI(since 0.12.4)\fP
.IP \(bu 2 .IP \(bu 2
\fB\fCexecp_interval = integer\fR : The command is executed again after \fB\fCexecp_interval\fR seconds from the moment it exits. If zero, the command is executed only once. \fI(since 0.12.4)\fP \fB\fCexecp_interval = integer\fR : The command is executed again after \fB\fCexecp_interval\fR seconds from the moment it exits. If zero, the command is executed only once. \fI(since 0.12.4)\fP

View File

@@ -314,6 +314,7 @@ panel_size = 94% 30
<h3 id="executor">Executor<a name="executor" href="#executor" class="md2man-permalink" title="permalink"></a></h3> <h3 id="executor">Executor<a name="executor" href="#executor" class="md2man-permalink" title="permalink"></a></h3>
<ul> <ul>
<li><p><code>execp = new</code> : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple <code>E</code>s in <code>panel_items</code>. <em>(since 0.12.4)</em></p></li> <li><p><code>execp = new</code> : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple <code>E</code>s in <code>panel_items</code>. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_name = text</code> : A name that can be used with <code>tint2-send refresh-execp</code> to re-execute the command.</p></li>
<li><p><code>execp_command = text</code> : Command to execute. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_command = text</code> : Command to execute. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_interval = integer</code> : The command is executed again after <code>execp_interval</code> seconds from the moment it exits. If zero, the command is executed only once. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_interval = integer</code> : The command is executed again after <code>execp_interval</code> seconds from the moment it exits. If zero, the command is executed only once. <em>(since 0.12.4)</em></p></li>
<li><p><code>execp_continuous = integer</code> : If non-zero, the last <code>execp_continuous</code> lines from the output of the command are displayed, every <code>execp_continuous</code> lines; this is useful for showing the output of commands that run indefinitely, such as <code>ping 127.0.0.1</code>. If zero, the output of the command is displayed after it finishes executing. <em>(since 0.12.4)</em></p></li> <li><p><code>execp_continuous = integer</code> : If non-zero, the last <code>execp_continuous</code> lines from the output of the command are displayed, every <code>execp_continuous</code> lines; this is useful for showing the output of commands that run indefinitely, such as <code>ping 127.0.0.1</code>. If zero, the output of the command is displayed after it finishes executing. <em>(since 0.12.4)</em></p></li>

View File

@@ -1,4 +1,4 @@
# TINT2 1 "2021-04-18" 17.0 # TINT2 1 "2021-12-04" 17.0.2
## NAME ## NAME
tint2 - lightweight panel/taskbar tint2 - lightweight panel/taskbar
@@ -593,6 +593,8 @@ The action semantics:
* `execp = new` : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple `E`s in `panel_items`. *(since 0.12.4)* * `execp = new` : Begins the configuration of a new executor plugin. Multiple such plugins are supported; just use multiple `E`s in `panel_items`. *(since 0.12.4)*
* `execp_name = text` : A name that can be used with `tint2-send refresh-execp` to re-execute the command.
* `execp_command = text` : Command to execute. *(since 0.12.4)* * `execp_command = text` : Command to execute. *(since 0.12.4)*
* `execp_interval = integer` : The command is executed again after `execp_interval` seconds from the moment it exits. If zero, the command is executed only once. *(since 0.12.4)* * `execp_interval = integer` : The command is executed again after `execp_interval` seconds from the moment it exits. If zero, the command is executed only once. *(since 0.12.4)*

View File

@@ -683,6 +683,14 @@ void add_entry(char *key, char *value)
/* Execp */ /* Execp */
else if (strcmp(key, "execp") == 0) { else if (strcmp(key, "execp") == 0) {
panel_config.execp_list = g_list_append(panel_config.execp_list, create_execp()); panel_config.execp_list = g_list_append(panel_config.execp_list, create_execp());
} else if (strcmp(key, "execp_name") == 0) {
Execp *execp = get_or_create_last_execp();
execp->backend->name[0] = 0;
if (strlen(value) > sizeof(execp->backend->name) - 1)
fprintf(stderr, RED "tint2: execp_name cannot be more than %ld bytes: '%s'" RESET "\n",
sizeof(execp->backend->name) - 1, value);
else if (strlen(value) > 0)
snprintf(execp->backend->name, sizeof(execp->backend->name), value);
} else if (strcmp(key, "execp_command") == 0) { } else if (strcmp(key, "execp_command") == 0) {
Execp *execp = get_or_create_last_execp(); Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->command); free_and_null(execp->backend->command);

View File

@@ -66,7 +66,8 @@ gpointer create_execp_frontend(gconstpointer arg, gpointer data)
execp_backend->backend->monitor, panel->monitor); execp_backend->backend->monitor, panel->monitor);
Execp *dummy = create_execp(); Execp *dummy = create_execp();
dummy->frontend = (ExecpFrontend *)calloc(1, sizeof(ExecpFrontend)); dummy->frontend = (ExecpFrontend *)calloc(1, sizeof(ExecpFrontend));
dummy->backend->instances = g_list_append(execp_backend->backend->instances, dummy); dummy->backend->instances = g_list_append(dummy->backend->instances, dummy);
dummy->dummy = true;
return dummy; return dummy;
} }
printf("Creating executor '%s' with monitor %d for panel on monitor %d\n", printf("Creating executor '%s' with monitor %d for panel on monitor %d\n",
@@ -89,7 +90,11 @@ void destroy_execp(void *obj)
free_and_null(execp->frontend); free_and_null(execp->frontend);
remove_area(&execp->area); remove_area(&execp->area);
free_area(&execp->area); free_area(&execp->area);
free_and_null(execp); if (execp->dummy) {
destroy_execp(execp);
} else {
free_and_null(execp);
}
} else { } else {
// This is a backend element // This is a backend element
destroy_timer(&execp->backend->timer); destroy_timer(&execp->backend->timer);

View File

@@ -20,6 +20,7 @@ extern bool debug_executors;
typedef struct ExecpBackend { typedef struct ExecpBackend {
// Config: // Config:
char name[21];
// Command to execute at a specified interval // Command to execute at a specified interval
char *command; char *command;
// Interval in seconds // Interval in seconds
@@ -97,6 +98,7 @@ typedef struct Execp {
ExecpBackend *backend; ExecpBackend *backend;
// Set only for frontend Execp items. // Set only for frontend Execp items.
ExecpFrontend *frontend; ExecpFrontend *frontend;
bool dummy;
} Execp; } Execp;
// Called before the config is read and panel_config/panels are created. // Called before the config is read and panel_config/panels are created.
@@ -153,4 +155,6 @@ void execp_default_font_changed();
void handle_execp_events(); void handle_execp_events();
void execp_force_update(Execp *execp);
#endif // EXECPLUGIN_H #endif // EXECPLUGIN_H

View File

@@ -32,7 +32,6 @@
#include <X11/extensions/Xdamage.h> #include <X11/extensions/Xdamage.h>
#include <Imlib2.h> #include <Imlib2.h>
#include <signal.h> #include <signal.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#include <time.h> #include <time.h>
@@ -545,6 +544,17 @@ void handle_x_event(XEvent *e)
handle_dnd_position(&e->xclient); handle_dnd_position(&e->xclient);
} else if (e->xclient.message_type == server.atom.XdndDrop) { } else if (e->xclient.message_type == server.atom.XdndDrop) {
handle_dnd_drop(&e->xclient); handle_dnd_drop(&e->xclient);
} else if (e->xclient.message_type == server.atom.TINT2_REFRESH_EXECP &&
e->xclient.format == 8) {
char name[sizeof(e->xclient.data.b) + 1] = {};
memcpy(name, e->xclient.data.b, sizeof(e->xclient.data.b));
for (GList *l = panel_config.execp_list; l; l = l->next) {
Execp *execp = (Execp *)l->data;
if (strncmp(name, execp->backend->name, sizeof(execp->backend->name) - 1) == 0) {
fprintf(stderr, "tint2: Refreshing executor: %s\n", name);
execp_force_update(execp);
}
}
} }
break; break;
} }

View File

@@ -292,9 +292,10 @@ void on_change_systray(void *obj)
} }
TrayWindow *traywin; TrayWindow *traywin;
GSList *l; GSList *l, *next;
int i; int i;
for (i = 1, l = systray.list_icons; l; i++, l = l->next) { for (i = 1, l = systray.list_icons; l; i++, l = next) {
next = l->next;
traywin = (TrayWindow *)l->data; traywin = (TrayWindow *)l->data;
traywin->y = posy; traywin->y = posy;

View File

@@ -1,12 +0,0 @@
ifeq ($(PREFIX),)
PREFIX := /usr/local
endif
tint2-send: tint2-send.c
$(CC) tint2-send.c -lX11 -o tint2-send
install: tint2-send
install -m 755 tint2-send $(DESTDIR)/$(PREFIX)/bin/
clean:
rm -f tint2-send

View File

@@ -45,8 +45,8 @@ int is_tint2(Window window)
XWindowAttributes attr = {}; XWindowAttributes attr = {};
if (!XGetWindowAttributes(display, window, &attr)) if (!XGetWindowAttributes(display, window, &attr))
return 0; return 0;
if (attr.map_state != IsViewable) // if (attr.map_state != IsViewable)
return 0; // return 0;
char *wm_class = get_property(window, XA_STRING, "WM_NAME"); char *wm_class = get_property(window, XA_STRING, "WM_NAME");
if (!wm_class) { if (!wm_class) {
@@ -60,11 +60,10 @@ int is_tint2(Window window)
return class_match; return class_match;
} }
void handle_tint2_window(Window window, void *arg) void handle_tint2_window(Window window, char *action, char **args)
{ {
if (!is_tint2(window)) if (!is_tint2(window))
return; return;
char *action = (char *)arg;
if (strcmp(action, "show") == 0) { if (strcmp(action, "show") == 0) {
fprintf(stderr, "Showing tint2 window: %lx\n", window); fprintf(stderr, "Showing tint2 window: %lx\n", window);
XEvent event = {}; XEvent event = {};
@@ -85,16 +84,40 @@ void handle_tint2_window(Window window, void *arg)
event.xcrossing.same_screen = True; event.xcrossing.same_screen = True;
XSendEvent(display, window, False, 0, &event); XSendEvent(display, window, False, 0, &event);
XFlush(display); XFlush(display);
} else if (strcmp(action, "refresh-execp") == 0) {
XEvent event = {};
char *name = args[0];
if (!name) {
fprintf(stderr, "Error: missing execp name\n");
return;
}
if (!name[0]) {
fprintf(stderr, "Error: empty execp name\n");
return;
}
if (strlen(name) > sizeof(event.xclient.data.b)) {
fprintf(stderr, "Error: execp name bigger than %ld bytes\n", sizeof(event.xclient.data.b));
return;
}
fprintf(stderr, "Refreshing execp '%s' for window: %lx\n", name, window);
event.xclient.type = ClientMessage;
event.xclient.window = window;
event.xclient.send_event = True;
event.xclient.message_type = XInternAtom(display, "_TINT2_REFRESH_EXECP", False);
event.xclient.format = 8;
strncpy(event.xclient.data.b, name, sizeof(event.xclient.data.b));
XSendEvent(display, window, False, 0, &event);
XFlush(display);
} else { } else {
fprintf(stderr, "Error: unknown action %s\n", action); fprintf(stderr, "Error: unknown action %s\n", action);
} }
} }
typedef void window_callback_t(Window window, void *arg); typedef void window_callback_t(Window window, char *action, char **args);
void walk_windows(Window node, window_callback_t *callback, void *arg) void walk_windows(Window node, window_callback_t *callback, char *action, char **args)
{ {
callback(node, arg); callback(node, action, args);
Window root = 0; Window root = 0;
Window parent = 0; Window parent = 0;
Window *children = 0; Window *children = 0;
@@ -104,7 +127,7 @@ void walk_windows(Window node, window_callback_t *callback, void *arg)
return; return;
} }
for (unsigned int i = 0; i < nchildren; i++) { for (unsigned int i = 0; i < nchildren; i++) {
walk_windows(children[i], callback, arg); walk_windows(children[i], callback, action, args);
} }
} }
@@ -118,11 +141,12 @@ int main(int argc, char **argv)
argc--, argv++; argc--, argv++;
if (!argc) { if (!argc) {
fprintf(stderr, "Usage: tint2-show [show|hide]\n"); fprintf(stderr, "Usage: tint2-send [show|hide|refresh-execp]\n");
exit(1); exit(1);
} }
char *action = argv[0]; char *action = argv[0];
walk_windows(DefaultRootWindow(display), handle_tint2_window, action); char **args = argv + 1;
walk_windows(DefaultRootWindow(display), handle_tint2_window, action, args);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4271,6 +4271,23 @@ void create_execp(GtkWidget *notebook, int i)
gtk_table_set_col_spacings(GTK_TABLE(table), COL_SPACING); gtk_table_set_col_spacings(GTK_TABLE(table), COL_SPACING);
row = 0, col = 2; row = 0, col = 2;
label = gtk_label_new(_("Name"));
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++;
executor->execp_name = gtk_entry_new();
gtk_widget_show(executor->execp_name);
gtk_entry_set_width_chars(GTK_ENTRY(executor->execp_name), 20);
gtk_entry_set_max_length(GTK_ENTRY(executor->execp_name), 20);
gtk_table_attach(GTK_TABLE(table), executor->execp_name, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
col++;
gtk_widget_set_tooltip_text(executor->execp_name,
_("Specifies a name that can be used with `tint2-send refresh-execp` to re-execute "
"the command."));
row++, col = 2;
label = gtk_label_new(_("Command")); label = gtk_label_new(_("Command"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_widget_show(label); gtk_widget_show(label);

View File

@@ -132,6 +132,7 @@ typedef struct Executor {
GtkWidget *container; GtkWidget *container;
GtkWidget *page_execp; GtkWidget *page_execp;
GtkWidget *page_label; GtkWidget *page_label;
GtkWidget *execp_name;
GtkWidget *execp_command, *execp_interval, *execp_has_icon, *execp_cache_icon, *execp_show_tooltip; GtkWidget *execp_command, *execp_interval, *execp_has_icon, *execp_cache_icon, *execp_show_tooltip;
GtkWidget *execp_continuous, *execp_markup, *execp_tooltip, *execp_monitor; GtkWidget *execp_continuous, *execp_markup, *execp_tooltip, *execp_monitor;
GtkWidget *execp_left_command, *execp_right_command; GtkWidget *execp_left_command, *execp_right_command;

View File

@@ -857,6 +857,7 @@ void config_write_execp(FILE *fp)
Executor *executor = &g_array_index(executors, Executor, i); Executor *executor = &g_array_index(executors, Executor, i);
fprintf(fp, "execp = new\n"); fprintf(fp, "execp = new\n");
fprintf(fp, "execp_name = %s\n", gtk_entry_get_text(GTK_ENTRY(executor->execp_name)));
fprintf(fp, "execp_command = %s\n", gtk_entry_get_text(GTK_ENTRY(executor->execp_command))); fprintf(fp, "execp_command = %s\n", gtk_entry_get_text(GTK_ENTRY(executor->execp_command)));
fprintf(fp, "execp_interval = %d\n", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(executor->execp_interval))); fprintf(fp, "execp_interval = %d\n", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(executor->execp_interval)));
fprintf(fp, fprintf(fp,
@@ -1962,6 +1963,8 @@ void add_entry(char *key, char *value)
/* Executor */ /* Executor */
else if (strcmp(key, "execp") == 0) { else if (strcmp(key, "execp") == 0) {
execp_create_new(); execp_create_new();
} else if (strcmp(key, "execp_name") == 0) {
gtk_entry_set_text(GTK_ENTRY(execp_get_last()->execp_name), value);
} else if (strcmp(key, "execp_command") == 0) { } else if (strcmp(key, "execp_command") == 0) {
gtk_entry_set_text(GTK_ENTRY(execp_get_last()->execp_command), value); gtk_entry_set_text(GTK_ENTRY(execp_get_last()->execp_command), value);
} else if (strcmp(key, "execp_interval") == 0) { } else if (strcmp(key, "execp_interval") == 0) {

View File

@@ -122,6 +122,9 @@ void server_init_atoms()
server.atom.XdndActionCopy = XInternAtom(server.display, "XdndActionCopy", False); server.atom.XdndActionCopy = XInternAtom(server.display, "XdndActionCopy", False);
server.atom.XdndFinished = XInternAtom(server.display, "XdndFinished", False); server.atom.XdndFinished = XInternAtom(server.display, "XdndFinished", False);
server.atom.TARGETS = XInternAtom(server.display, "TARGETS", False); server.atom.TARGETS = XInternAtom(server.display, "TARGETS", False);
// tint2 atoms
server.atom.TINT2_REFRESH_EXECP = XInternAtom(server.display, "_TINT2_REFRESH_EXECP", False);
} }
const char *GetAtomName(Display *disp, Atom a) const char *GetAtomName(Display *disp, Atom a)

View File

@@ -91,6 +91,7 @@ typedef struct Global_atom {
Atom XdndActionCopy; Atom XdndActionCopy;
Atom XdndFinished; Atom XdndFinished;
Atom TARGETS; Atom TARGETS;
Atom TINT2_REFRESH_EXECP;
} Global_atom; } Global_atom;
typedef struct Property { typedef struct Property {

View File

@@ -85,7 +85,6 @@ static void sigchld_handler(int sig)
int savedErrno = errno; int savedErrno = errno;
ssize_t unused = write(sigchild_pipe[1], "x", 1); ssize_t unused = write(sigchild_pipe[1], "x", 1);
(void)unused; (void)unused;
fsync(sigchild_pipe[1]);
errno = savedErrno; errno = savedErrno;
} }

View File

@@ -169,31 +169,40 @@ int get_window_desktop(Window win)
return best_match; return best_match;
} }
#define swap(a, b) do { __typeof__(a) _tmp = (a); (a) = (b); (b) = _tmp; } while(0)
int get_interval_overlap(int a1, int a2, int b1, int b2)
{
if (a1 > b1) {
swap(a1, b1);
swap(a2, b2);
}
if (b1 <= a2)
return a2 - b1;
return 0;
}
int get_window_monitor(Window win) int get_window_monitor(Window win)
{ {
int x, y, w, h; int x, y, w, h;
get_window_coordinates(win, &x, &y, &w, &h); get_window_coordinates(win, &x, &y, &w, &h);
int best_match = -1; int best_match = 0;
int match_right = 0; int best_area = -1;
int match_bottom = 0;
// There is an ambiguity when a window is right on the edge between screens.
// In that case, prefer the monitor which is on the right and bottom of the window's top-left corner.
for (int i = 0; i < server.num_monitors; i++) { for (int i = 0; i < server.num_monitors; i++) {
if (x >= server.monitors[i].x && x <= (server.monitors[i].x + server.monitors[i].width) && int commonx = get_interval_overlap(x, x + w, server.monitors[i].x, server.monitors[i].x + server.monitors[i].width);
y >= server.monitors[i].y && y <= (server.monitors[i].y + server.monitors[i].height)) { int commony = get_interval_overlap(y, y + h, server.monitors[i].y, server.monitors[i].y + server.monitors[i].height);
int current_right = x < (server.monitors[i].x + server.monitors[i].width); int area = commonx * commony;
int current_bottom = y < (server.monitors[i].y + server.monitors[i].height); if (0)
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { printf("Monitor %d (%dx%d+%dx%d): win (%dx%d+%dx%d) area %dx%d=%d\n",
best_match = i; i, server.monitors[i].x, server.monitors[i].y, server.monitors[i].width, server.monitors[i].height,
} x, y, w, h,
commonx, commony, area);
if (area > best_area) {
best_area = area;
best_match = i;
} }
} }
if (best_match < 0)
best_match = 0;
// 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; return best_match;
} }