Commit 3f84d5d1 authored by o9000's avatar o9000

Merged execplugin from tint2-mods2 (no config GUI yet)

parent 33645f9b
......@@ -47,6 +47,7 @@ include_directories( ${PROJECT_BINARY_DIR}
src/launcher
src/tooltip
src/util
src/execplugin
src/freespace
${X11_INCLUDE_DIRS}
${PANGOCAIRO_INCLUDE_DIRS}
......@@ -73,6 +74,7 @@ set( SOURCES src/config.c
src/taskbar/taskbar.c
src/taskbar/taskbarname.c
src/tooltip/tooltip.c
src/execplugin/execplugin.c
src/freespace/freespace.c
src/util/area.c
src/util/common.c
......
2015-11-21 master
2015-12-05 master
- Enhancements:
- Support for NETWM viewports (as in Compiz) (issue #94)
- New plugin: executor
2015-11-12 0.12.3
- Enhancements:
- Battery: Multiple batteries are now supported under Linux (issue #139;
......
......@@ -52,6 +52,7 @@
#include "window.h"
#include "tooltip.h"
#include "timer.h"
#include "execplugin.h"
#ifdef ENABLE_BATTERY
#include "battery.h"
......@@ -199,6 +200,15 @@ void load_launcher_app_dir(const char *path)
g_list_free(files);
}
Execp *get_or_create_last_execp()
{
if (!panel_config.execp_list) {
fprintf(stderr, "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;
}
void add_entry(char *key, char *value)
{
char *value1 = 0, *value2 = 0, *value3 = 0;
......@@ -498,6 +508,109 @@ void add_entry(char *key, char *value)
#endif
}
/* Execp */
else if (strcmp(key, "execp") == 0) {
panel_config.execp_list = g_list_append(panel_config.execp_list, create_execp());
} else if (strcmp(key, "execp_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->command);
if (strlen(value) > 0)
execp->backend->command = strdup(value);
} else if (strcmp(key, "execp_interval") == 0) {
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");
} else {
execp->backend->interval = v;
}
} else if (strcmp(key, "execp_has_icon") == 0) {
Execp *execp = get_or_create_last_execp();
execp->backend->has_icon = atoi(value);
} else if (strcmp(key, "execp_continuous") == 0) {
Execp *execp = get_or_create_last_execp();
execp->backend->continuous = atoi(value);
} else if (strcmp(key, "execp_cache_icon") == 0) {
Execp *execp = get_or_create_last_execp();
execp->backend->cache_icon = atoi(value);
} else if (strcmp(key, "execp_tooltip") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->tooltip);
execp->backend->tooltip = strdup(value);
} else if (strcmp(key, "execp_font") == 0) {
Execp *execp = get_or_create_last_execp();
pango_font_description_free(execp->backend->font_desc);
execp->backend->font_desc = pango_font_description_from_string(value);
} else if (strcmp(key, "execp_font_color") == 0) {
Execp *execp = get_or_create_last_execp();
extract_values(value, &value1, &value2, &value3);
get_color(value1, execp->backend->font_color.rgb);
if (value2)
execp->backend->font_color.alpha = atoi(value2) / 100.0;
else
execp->backend->font_color.alpha = 0.5;
} else if (strcmp(key, "execp_padding") == 0) {
Execp *execp = get_or_create_last_execp();
extract_values(value, &value1, &value2, &value3);
execp->backend->paddingxlr = execp->backend->paddingx = atoi(value1);
if (value2)
execp->backend->paddingy = atoi(value2);
else
execp->backend->paddingy = 0;
if (value3)
execp->backend->paddingx = atoi(value3);
} else if (strcmp(key, "execp_background_id") == 0) {
Execp *execp = get_or_create_last_execp();
int id = atoi(value);
id = (id < backgrounds->len && id >= 0) ? id : 0;
execp->backend->bg = &g_array_index(backgrounds, Background, id);
} else if (strcmp(key, "execp_centered") == 0) {
Execp *execp = get_or_create_last_execp();
execp->backend->centered = atoi(value);
} else if (strcmp(key, "execp_icon_w") == 0) {
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");
} else {
execp->backend->icon_w = v;
}
} else if (strcmp(key, "execp_icon_h") == 0) {
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");
} else {
execp->backend->icon_h = v;
}
} else if (strcmp(key, "execp_lclick_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->lclick_command);
if (strlen(value) > 0)
execp->backend->lclick_command = strdup(value);
} else if (strcmp(key, "execp_mclick_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->mclick_command);
if (strlen(value) > 0)
execp->backend->mclick_command = strdup(value);
} else if (strcmp(key, "execp_rclick_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->rclick_command);
if (strlen(value) > 0)
execp->backend->rclick_command = strdup(value);
} else if (strcmp(key, "execp_uwheel_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->uwheel_command);
if (strlen(value) > 0)
execp->backend->uwheel_command = strdup(value);
} else if (strcmp(key, "execp_dwheel_command") == 0) {
Execp *execp = get_or_create_last_execp();
free_and_null(execp->backend->dwheel_command);
if (strlen(value) > 0)
execp->backend->dwheel_command = strdup(value);
}
/* Clock */
else if (strcmp(key, "time1_format") == 0) {
if (new_config_file == 0) {
......
This diff is collapsed.
#ifndef EXECPLUGIN_H
#define EXECPLUGIN_H
#include <sys/time.h>
#include <pango/pangocairo.h>
#include "area.h"
#include "common.h"
#include "timer.h"
// Architecture:
// Panel panel_config contains an array of Execp, each storing all config options and all the state variables.
// Only these run commands.
//
// Tint2 maintains an array of Panels, one for each monitor. Each stores an array of Execp which was initially copied
// from panel_config. Each works as a frontend to the corresponding Execp in panel_config as backend, using the
// backend's config and state variables.
typedef struct ExecpBackend {
// Config:
// Command to execute at a specified interval
char *command;
// Interval in seconds
int interval;
// 1 if first line of output is an icon path
gboolean has_icon;
gboolean cache_icon;
int icon_w;
int icon_h;
char *tooltip;
gboolean centered;
PangoFontDescription *font_desc;
Color font_color;
int continuous;
char *lclick_command;
char *mclick_command;
char *rclick_command;
char *uwheel_command;
char *dwheel_command;
// paddingxlr = horizontal padding left/right
// paddingx = horizontal padding between childs
int paddingxlr, paddingx, paddingy;
Background *bg;
// Backend state:
timeout *timer;
int child_pipe;
pid_t child;
// Command output buffer
char *buf_output;
int buf_length;
int buf_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];
// The time the last command was started
time_t last_update_start_time;
// The time the last output was obtained
time_t last_update_finish_time;
// The time it took to execute last command
time_t last_update_duration;
// List of Execp which are frontends for this backend, one for each panel
GList *instances;
} ExecpBackend;
typedef struct ExecpFrontend {
// Frontend state:
int iconx;
int icony;
int textx;
int texty;
int textw;
int texth;
} ExecpFrontend;
typedef struct Execp {
Area area;
// All elements have the backend pointer set. However only backend elements have ownership.
ExecpBackend *backend;
// Set only for frontend Execp items.
ExecpFrontend *frontend;
} Execp;
// Called before the config is read and panel_config/panels are created.
// Afterwards, the config parsing code creates the array of Execp in panel_config and populates the configuration fields
// in the backend.
// Probably does nothing.
void default_execp();
// Creates a new Execp item with only the backend field set. The state is NOT initialized. The config is initialized to
// the default values.
// This will be used by the config code to populate its backedn config fields.
Execp *create_execp();
void destroy_execp(void *obj);
// Called after the config is read and panel_config is populated, but before panels are created.
// Initializes the state of the backend items.
// panel_config.panel_items is used to determine which backend items are enabled. The others should be destroyed and
// removed from panel_config.execp_list.
void init_execp();
// Called after each on-screen panel is created, with a pointer to the panel.
// Initializes the state of the frontend items. Also adds a pointer to it in backend->instances.
// At this point the Area has not been added yet to the GUI tree, but it will be added right away.
void init_execp_panel(void *panel);
// Called just before the panels are destroyed. Afterwards, tint2 exits or restarts and reads the config again.
// Releases all frontends and then all the backends.
// The frontend items are not freed by this function, only their members. The items are Areas which are freed in the
// GUI element tree cleanup function (remove_area).
void cleanup_execp();
// Called on draw, obj = pointer to the front-end Execp item.
void draw_execp(void *obj, cairo_t *c);
// Called on resize, obj = pointer to the front-end Execp item.
// Returns 1 if the new size is different than the previous size.
gboolean resize_execp(void *obj);
// Called on mouse click event.
void execp_action(void *obj, int button);
// Called to check if new output from the command can be read.
// No command might be running.
// Returns 1 if the output has been updated and a redraw is needed.
gboolean read_execp(void *obj);
#endif // EXECPLUGIN_H
......@@ -163,6 +163,7 @@ void init_panel()
init_battery();
#endif
init_taskbar();
init_execp();
// number of panels (one monitor or 'all' monitors)
if (panel_config.monitor >= 0)
......@@ -212,6 +213,8 @@ void init_panel()
init_clock_panel(p);
if (panel_items_order[k] == 'F' && !strstr(panel_items_order, "T"))
init_freespace_panel(p);
if (panel_items_order[k] == 'E')
init_execp_panel(p);
}
set_panel_items_order(p);
......@@ -512,6 +515,7 @@ void set_panel_items_order(Panel *p)
p->area.children = 0;
}
int i_execp = 0;
for (int k = 0; k < strlen(panel_items_order); k++) {
if (panel_items_order[k] == 'L') {
p->area.children = g_list_append(p->area.children, &p->launcher);
......@@ -533,6 +537,12 @@ void set_panel_items_order(Panel *p)
p->area.children = g_list_append(p->area.children, &p->clock);
if (panel_items_order[k] == 'F')
p->area.children = g_list_append(p->area.children, &p->freespace);
if (panel_items_order[k] == 'E') {
GList *item = g_list_nth(p->execp_list, i_execp);
i_execp++;
if (item)
p->area.children = g_list_append(p->area.children, (Area*)item->data);
}
}
initialize_positions(&p->area, 0);
}
......@@ -866,6 +876,22 @@ int click_battery(Panel *panel, int x, int y)
}
#endif
Execp *click_execp(Panel *panel, int x, int y)
{
GList *l;
for (l = panel->execp_list; l; l = l->next) {
Execp *execp = (Execp *)l->data;
if (panel_horizontal) {
if (execp->area.on_screen && x >= execp->area.posx && x <= (execp->area.posx + execp->area.width))
return execp;
} else {
if (execp->area.on_screen && y >= execp->area.posy && y <= (execp->area.posy + execp->area.height))
return execp;
}
}
return NULL;
}
Area *click_area(Panel *panel, int x, int y)
{
Area *result = &panel->area;
......
......@@ -21,6 +21,7 @@
#include "systraybar.h"
#include "launcher.h"
#include "freespace.h"
#include "execplugin.h"
#ifdef ENABLE_BATTERY
#include "battery.h"
......@@ -123,6 +124,7 @@ typedef struct Panel {
Launcher launcher;
FreeSpace freespace;
GList *execp_list;
// Autohide
gboolean is_hidden;
......@@ -170,6 +172,7 @@ gboolean click_battery(Panel *panel, int x, int y);
#endif
Area *click_area(Panel *panel, int x, int y);
Execp *click_execp(Panel *panel, int x, int y);
void autohide_show(void *p);
void autohide_hide(void *p);
......
......@@ -121,6 +121,7 @@ void init(int argc, char *argv[])
default_launcher();
default_taskbar();
default_tooltip();
default_execp();
default_panel();
// read options
......@@ -314,6 +315,7 @@ void init_X11_post_config()
void cleanup()
{
cleanup_execp();
cleanup_systray();
cleanup_tooltip();
cleanup_clock();
......@@ -477,6 +479,8 @@ int tint2_handles_click(Panel *panel, XButtonEvent *e)
return 0;
}
#endif
if (click_execp(panel, e->x, e->y))
return 1;
return 0;
}
......@@ -631,6 +635,15 @@ void event_button_release(XEvent *e)
}
#endif
Execp *execp = click_execp(panel, e->xbutton.x, e->xbutton.y);
if (execp) {
execp_action(execp, e->xbutton.button);
if (panel_layer == BOTTOM_LAYER)
XLowerWindow(server.dsp, 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) {
......@@ -1346,6 +1359,14 @@ start:
FD_SET(sn_pipe[0], &fdset);
maxfd = maxfd < sn_pipe[0] ? sn_pipe[0] : maxfd;
}
for (GList *l = panel_config.execp_list; l; l = l->next) {
Execp *execp = (Execp *)l->data;
int fd = execp->backend->child_pipe;
if (fd > 0) {
FD_SET(fd, &fdset);
maxfd = maxfd < fd ? fd : maxfd;
}
}
if (ufd > 0) {
FD_SET(ufd, &fdset);
maxfd = maxfd < ufd ? ufd : maxfd;
......@@ -1363,6 +1384,17 @@ start:
sigchld_handler_async();
}
}
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 = l_instance->data;
instance->area.resize_needed = TRUE;
panel_refresh = TRUE;
}
}
}
if (XPending(server.dsp) > 0) {
XEvent e;
XNextEvent(server.dsp, &e);
......
......@@ -97,4 +97,6 @@ void draw_rect(cairo_t *c, double x, double y, double w, double h, double r);
// Clears the pixmap (with transparent color)
void clear_pixmap(Pixmap p, int x, int y, int w, int h);
#define free_and_null(p) { free(p); p = NULL; }
#endif
......@@ -161,3 +161,5 @@ src/battery/openbsd.c
src/util/uevent.c
src/util/uevent.h
.clang-format
src/execplugin/execplugin.c
src/execplugin/execplugin.h
......@@ -20,3 +20,4 @@
po
src/tint2conf/po
src/freespace
src/execplugin
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment