Changed indentation everywhere
This commit is contained in:
1636
src/util/area.c
1636
src/util/area.c
File diff suppressed because it is too large
Load Diff
178
src/util/area.h
178
src/util/area.h
@@ -121,125 +121,125 @@
|
||||
// The Area's _get_tooltip_text member must point to this function.
|
||||
|
||||
typedef enum BorderMask {
|
||||
BORDER_TOP = 1 << 0,
|
||||
BORDER_BOTTOM = 1 << 1,
|
||||
BORDER_LEFT = 1 << 2,
|
||||
BORDER_RIGHT = 1 << 3
|
||||
BORDER_TOP = 1 << 0,
|
||||
BORDER_BOTTOM = 1 << 1,
|
||||
BORDER_LEFT = 1 << 2,
|
||||
BORDER_RIGHT = 1 << 3
|
||||
} BorderMask;
|
||||
|
||||
#define BORDER_ALL (BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT)
|
||||
|
||||
typedef struct Border {
|
||||
// It's essential that the first member is color
|
||||
Color color;
|
||||
// Width in pixels
|
||||
int width;
|
||||
// Corner radius
|
||||
int radius;
|
||||
// Mask: bitwise OR of BorderMask
|
||||
int mask;
|
||||
// It's essential that the first member is color
|
||||
Color color;
|
||||
// Width in pixels
|
||||
int width;
|
||||
// Corner radius
|
||||
int radius;
|
||||
// Mask: bitwise OR of BorderMask
|
||||
int mask;
|
||||
} Border;
|
||||
|
||||
typedef enum MouseState { MOUSE_NORMAL = 0, MOUSE_OVER = 1, MOUSE_DOWN = 2, MOUSE_STATE_COUNT } MouseState;
|
||||
|
||||
typedef struct Background {
|
||||
// Normal state
|
||||
Color fill_color;
|
||||
Border border;
|
||||
// On mouse hover
|
||||
Color fill_color_hover;
|
||||
Color border_color_hover;
|
||||
// On mouse press
|
||||
Color fill_color_pressed;
|
||||
Color border_color_pressed;
|
||||
// Pointer to a GradientClass or NULL, no ownership
|
||||
GradientClass *gradients[MOUSE_STATE_COUNT];
|
||||
// Normal state
|
||||
Color fill_color;
|
||||
Border border;
|
||||
// On mouse hover
|
||||
Color fill_color_hover;
|
||||
Color border_color_hover;
|
||||
// On mouse press
|
||||
Color fill_color_pressed;
|
||||
Color border_color_pressed;
|
||||
// Pointer to a GradientClass or NULL, no ownership
|
||||
GradientClass *gradients[MOUSE_STATE_COUNT];
|
||||
} Background;
|
||||
|
||||
typedef enum Layout {
|
||||
LAYOUT_DYNAMIC,
|
||||
LAYOUT_FIXED,
|
||||
LAYOUT_DYNAMIC,
|
||||
LAYOUT_FIXED,
|
||||
} Layout;
|
||||
|
||||
typedef enum Alignment {
|
||||
ALIGN_LEFT = 0,
|
||||
ALIGN_CENTER = 1,
|
||||
ALIGN_RIGHT = 2,
|
||||
ALIGN_LEFT = 0,
|
||||
ALIGN_CENTER = 1,
|
||||
ALIGN_RIGHT = 2,
|
||||
} Alignment;
|
||||
|
||||
struct Panel;
|
||||
|
||||
typedef struct Area {
|
||||
// Position relative to the panel window
|
||||
int posx, posy;
|
||||
// Size, including borders
|
||||
int width, height;
|
||||
int old_width, old_height;
|
||||
Background *bg;
|
||||
// Each element is a GradientInstance attached to this Area (list can be empty)
|
||||
GList *gradient_instances_by_state[MOUSE_STATE_COUNT];
|
||||
// Each element is a GradientInstance that depends on this Area's geometry (position or size)
|
||||
GList *dependent_gradients;
|
||||
// List of children, each one a pointer to Area
|
||||
GList *children;
|
||||
// Pointer to the parent Area or NULL
|
||||
void *parent;
|
||||
// Pointer to the Panel that contains this Area
|
||||
void *panel;
|
||||
Layout size_mode;
|
||||
Alignment alignment;
|
||||
gboolean has_mouse_over_effect;
|
||||
gboolean has_mouse_press_effect;
|
||||
// TODO padding/spacing is a clusterfuck
|
||||
// paddingxlr = padding
|
||||
// paddingy = vertical padding, sometimes
|
||||
// paddingx = spacing
|
||||
int paddingxlr, paddingx, paddingy;
|
||||
MouseState mouse_state;
|
||||
// Set to non-zero if the Area is visible. An object may exist but stay hidden.
|
||||
gboolean on_screen;
|
||||
// Set to non-zero if the size of the Area has to be recalculated.
|
||||
gboolean resize_needed;
|
||||
// Set to non-zero if the Area has to be redrawn.
|
||||
// Do not set this directly; use schedule_redraw() instead.
|
||||
gboolean _redraw_needed;
|
||||
// Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called
|
||||
gboolean _changed;
|
||||
// This is the pixmap on which the Area is rendered. Render to it directly if needed.
|
||||
Pixmap pix;
|
||||
Pixmap pix_by_state[MOUSE_STATE_COUNT];
|
||||
char name[32];
|
||||
// Position relative to the panel window
|
||||
int posx, posy;
|
||||
// Size, including borders
|
||||
int width, height;
|
||||
int old_width, old_height;
|
||||
Background *bg;
|
||||
// Each element is a GradientInstance attached to this Area (list can be empty)
|
||||
GList *gradient_instances_by_state[MOUSE_STATE_COUNT];
|
||||
// Each element is a GradientInstance that depends on this Area's geometry (position or size)
|
||||
GList *dependent_gradients;
|
||||
// List of children, each one a pointer to Area
|
||||
GList *children;
|
||||
// Pointer to the parent Area or NULL
|
||||
void *parent;
|
||||
// Pointer to the Panel that contains this Area
|
||||
void *panel;
|
||||
Layout size_mode;
|
||||
Alignment alignment;
|
||||
gboolean has_mouse_over_effect;
|
||||
gboolean has_mouse_press_effect;
|
||||
// TODO padding/spacing is a clusterfuck
|
||||
// paddingxlr = padding
|
||||
// paddingy = vertical padding, sometimes
|
||||
// paddingx = spacing
|
||||
int paddingxlr, paddingx, paddingy;
|
||||
MouseState mouse_state;
|
||||
// Set to non-zero if the Area is visible. An object may exist but stay hidden.
|
||||
gboolean on_screen;
|
||||
// Set to non-zero if the size of the Area has to be recalculated.
|
||||
gboolean resize_needed;
|
||||
// Set to non-zero if the Area has to be redrawn.
|
||||
// Do not set this directly; use schedule_redraw() instead.
|
||||
gboolean _redraw_needed;
|
||||
// Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called
|
||||
gboolean _changed;
|
||||
// This is the pixmap on which the Area is rendered. Render to it directly if needed.
|
||||
Pixmap pix;
|
||||
Pixmap pix_by_state[MOUSE_STATE_COUNT];
|
||||
char name[32];
|
||||
|
||||
// Callbacks
|
||||
// Callbacks
|
||||
|
||||
// Called on draw before any drawing takes place, obj = pointer to the Area
|
||||
void (*_clear)(void *obj);
|
||||
// Called on draw before any drawing takes place, obj = pointer to the Area
|
||||
void (*_clear)(void *obj);
|
||||
|
||||
// Called on draw, obj = pointer to the Area
|
||||
void (*_draw_foreground)(void *obj, cairo_t *c);
|
||||
// Called on draw, obj = pointer to the Area
|
||||
void (*_draw_foreground)(void *obj, cairo_t *c);
|
||||
|
||||
// Called on resize, obj = pointer to the Area
|
||||
// Returns 1 if the new size is different than the previous size.
|
||||
gboolean (*_resize)(void *obj);
|
||||
// Called on resize, obj = pointer to the Area
|
||||
// Returns 1 if the new size is different than the previous size.
|
||||
gboolean (*_resize)(void *obj);
|
||||
|
||||
// Called before resize, obj = pointer to the Area
|
||||
// Returns the desired size of the Area
|
||||
int (*_compute_desired_size)(void *obj);
|
||||
// Called before resize, obj = pointer to the Area
|
||||
// Returns the desired size of the Area
|
||||
int (*_compute_desired_size)(void *obj);
|
||||
|
||||
// Implemented only to override the default layout algorithm for this widget.
|
||||
// For example, if this widget is a cell in a table, its position and size should be computed here.
|
||||
void (*_on_change_layout)(void *obj);
|
||||
// Implemented only to override the default layout algorithm for this widget.
|
||||
// For example, if this widget is a cell in a table, its position and size should be computed here.
|
||||
void (*_on_change_layout)(void *obj);
|
||||
|
||||
// Returns a copy of the tooltip to be displayed for this widget.
|
||||
// The caller takes ownership of the pointer.
|
||||
char *(*_get_tooltip_text)(void *obj);
|
||||
// Returns a copy of the tooltip to be displayed for this widget.
|
||||
// The caller takes ownership of the pointer.
|
||||
char *(*_get_tooltip_text)(void *obj);
|
||||
|
||||
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
|
||||
// Leave this to NULL to use a default implementation.
|
||||
gboolean (*_is_under_mouse)(void *obj, int x, int y);
|
||||
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
|
||||
// Leave this to NULL to use a default implementation.
|
||||
gboolean (*_is_under_mouse)(void *obj, int x, int y);
|
||||
|
||||
// Prints the geometry of the object on stderr, with left indentation of indent spaces.
|
||||
void (*_dump_geometry)(void *obj, int indent);
|
||||
// Prints the geometry of the object on stderr, with left indentation of indent spaces.
|
||||
void (*_dump_geometry)(void *obj, int indent);
|
||||
} Area;
|
||||
|
||||
// Initializes the Background member to default values.
|
||||
|
||||
168
src/util/cache.c
168
src/util/cache.c
@@ -32,129 +32,129 @@
|
||||
|
||||
void init_cache(Cache *cache)
|
||||
{
|
||||
if (cache->_table)
|
||||
free_cache(cache);
|
||||
cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
if (cache->_table)
|
||||
free_cache(cache);
|
||||
cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
}
|
||||
|
||||
void free_cache(Cache *cache)
|
||||
{
|
||||
if (cache->_table)
|
||||
g_hash_table_destroy(cache->_table);
|
||||
cache->_table = NULL;
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
if (cache->_table)
|
||||
g_hash_table_destroy(cache->_table);
|
||||
cache->_table = NULL;
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
}
|
||||
|
||||
void load_cache(Cache *cache, const gchar *cache_path)
|
||||
{
|
||||
init_cache(cache);
|
||||
init_cache(cache);
|
||||
|
||||
cache->loaded = TRUE;
|
||||
cache->loaded = TRUE;
|
||||
|
||||
int fd = open(cache_path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
flock(fd, LOCK_SH);
|
||||
int fd = open(cache_path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
flock(fd, LOCK_SH);
|
||||
|
||||
FILE *f = fopen(cache_path, "rt");
|
||||
if (!f)
|
||||
goto unlock;
|
||||
FILE *f = fopen(cache_path, "rt");
|
||||
if (!f)
|
||||
goto unlock;
|
||||
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
|
||||
while (getline(&line, &line_size, f) >= 0) {
|
||||
char *key, *value;
|
||||
while (getline(&line, &line_size, f) >= 0) {
|
||||
char *key, *value;
|
||||
|
||||
size_t line_len = strlen(line);
|
||||
gboolean has_newline = FALSE;
|
||||
if (line_len >= 1) {
|
||||
if (line[line_len - 1] == '\n') {
|
||||
line[line_len - 1] = '\0';
|
||||
line_len--;
|
||||
has_newline = TRUE;
|
||||
}
|
||||
}
|
||||
if (!has_newline)
|
||||
break;
|
||||
size_t line_len = strlen(line);
|
||||
gboolean has_newline = FALSE;
|
||||
if (line_len >= 1) {
|
||||
if (line[line_len - 1] == '\n') {
|
||||
line[line_len - 1] = '\0';
|
||||
line_len--;
|
||||
has_newline = TRUE;
|
||||
}
|
||||
}
|
||||
if (!has_newline)
|
||||
break;
|
||||
|
||||
if (line_len == 0)
|
||||
continue;
|
||||
if (line_len == 0)
|
||||
continue;
|
||||
|
||||
if (parse_line(line, &key, &value)) {
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
free(key);
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(f);
|
||||
if (parse_line(line, &key, &value)) {
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
free(key);
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(f);
|
||||
|
||||
unlock:
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void write_cache_line(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
gchar *k = key;
|
||||
gchar *v = value;
|
||||
FILE *f = user_data;
|
||||
gchar *k = key;
|
||||
gchar *v = value;
|
||||
FILE *f = user_data;
|
||||
|
||||
fprintf(f, "%s=%s\n", k, v);
|
||||
fprintf(f, "%s=%s\n", k, v);
|
||||
}
|
||||
|
||||
void save_cache(Cache *cache, const gchar *cache_path)
|
||||
{
|
||||
int fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
|
||||
if (fd == -1) {
|
||||
gchar *dir_path = g_path_get_dirname(cache_path);
|
||||
g_mkdir_with_parents(dir_path, 0700);
|
||||
g_free(dir_path);
|
||||
fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
|
||||
}
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
|
||||
return;
|
||||
}
|
||||
flock(fd, LOCK_EX);
|
||||
int fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
|
||||
if (fd == -1) {
|
||||
gchar *dir_path = g_path_get_dirname(cache_path);
|
||||
g_mkdir_with_parents(dir_path, 0700);
|
||||
g_free(dir_path);
|
||||
fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
|
||||
}
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, RED "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");
|
||||
goto unlock;
|
||||
}
|
||||
g_hash_table_foreach(cache->_table, write_cache_line, f);
|
||||
fclose(f);
|
||||
cache->dirty = FALSE;
|
||||
FILE *f = fopen(cache_path, "w");
|
||||
if (!f) {
|
||||
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
|
||||
goto unlock;
|
||||
}
|
||||
g_hash_table_foreach(cache->_table, write_cache_line, f);
|
||||
fclose(f);
|
||||
cache->dirty = FALSE;
|
||||
|
||||
unlock:
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const gchar *get_from_cache(Cache *cache, const gchar *key)
|
||||
{
|
||||
if (!cache->_table)
|
||||
return NULL;
|
||||
return g_hash_table_lookup(cache->_table, key);
|
||||
if (!cache->_table)
|
||||
return NULL;
|
||||
return g_hash_table_lookup(cache->_table, key);
|
||||
}
|
||||
|
||||
void add_to_cache(Cache *cache, const gchar *key, const gchar *value)
|
||||
{
|
||||
if (!cache->_table)
|
||||
init_cache(cache);
|
||||
if (!cache->_table)
|
||||
init_cache(cache);
|
||||
|
||||
if (!key || !value)
|
||||
return;
|
||||
if (!key || !value)
|
||||
return;
|
||||
|
||||
gchar *old_value = g_hash_table_lookup(cache->_table, key);
|
||||
if (old_value && g_str_equal(old_value, value))
|
||||
return;
|
||||
gchar *old_value = g_hash_table_lookup(cache->_table, key);
|
||||
if (old_value && g_str_equal(old_value, value))
|
||||
return;
|
||||
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
cache->dirty = TRUE;
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
cache->dirty = TRUE;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
// A cache with string keys and values, backed by a file.
|
||||
// The strings must not be NULL and are stripped of any whitespace at start and end.
|
||||
typedef struct Cache {
|
||||
gboolean dirty;
|
||||
gboolean loaded;
|
||||
GHashTable *_table;
|
||||
gboolean dirty;
|
||||
gboolean loaded;
|
||||
GHashTable *_table;
|
||||
} Cache;
|
||||
|
||||
// Initializes the cache. You can also call load_cache directly if you set the memory contents to zero first.
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
#include "color.h"
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
#define COLOR_H
|
||||
|
||||
typedef struct Color {
|
||||
// Values are in [0, 1], with 0 meaning no intensity.
|
||||
double rgb[3];
|
||||
// Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque.
|
||||
double alpha;
|
||||
// Values are in [0, 1], with 0 meaning no intensity.
|
||||
double rgb[3];
|
||||
// Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque.
|
||||
double alpha;
|
||||
} Color;
|
||||
|
||||
#endif // COLOR_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,19 +24,19 @@
|
||||
|
||||
// mouse actions
|
||||
typedef enum MouseAction {
|
||||
NONE = 0,
|
||||
CLOSE,
|
||||
TOGGLE,
|
||||
ICONIFY,
|
||||
SHADE,
|
||||
TOGGLE_ICONIFY,
|
||||
MAXIMIZE_RESTORE,
|
||||
MAXIMIZE,
|
||||
RESTORE,
|
||||
DESKTOP_LEFT,
|
||||
DESKTOP_RIGHT,
|
||||
NEXT_TASK,
|
||||
PREV_TASK
|
||||
NONE = 0,
|
||||
CLOSE,
|
||||
TOGGLE,
|
||||
ICONIFY,
|
||||
SHADE,
|
||||
TOGGLE_ICONIFY,
|
||||
MAXIMIZE_RESTORE,
|
||||
MAXIMIZE,
|
||||
RESTORE,
|
||||
DESKTOP_LEFT,
|
||||
DESKTOP_RIGHT,
|
||||
NEXT_TASK,
|
||||
PREV_TASK
|
||||
} MouseAction;
|
||||
|
||||
#define ALL_DESKTOPS 0xFFFFFFFF
|
||||
@@ -94,16 +94,16 @@ void create_heuristic_mask(DATA32 *data, int w, int h);
|
||||
void render_image(Drawable d, int x, int y);
|
||||
|
||||
void get_text_size2(PangoFontDescription *font,
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int panel_height,
|
||||
int panel_with,
|
||||
char *text,
|
||||
int len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup);
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int panel_height,
|
||||
int panel_with,
|
||||
char *text,
|
||||
int len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup);
|
||||
|
||||
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow);
|
||||
|
||||
@@ -125,10 +125,10 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr
|
||||
gint cmp_ptr(gconstpointer a, gconstpointer b);
|
||||
|
||||
#define free_and_null(p) \
|
||||
{ \
|
||||
free(p); \
|
||||
p = NULL; \
|
||||
}
|
||||
{ \
|
||||
free(p); \
|
||||
p = NULL; \
|
||||
}
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 33, 4)
|
||||
GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data);
|
||||
|
||||
@@ -8,116 +8,116 @@
|
||||
|
||||
gboolean read_double(const char *str, double *value)
|
||||
{
|
||||
if (!str[0])
|
||||
return FALSE;
|
||||
char *end;
|
||||
*value = strtod(str, &end);
|
||||
if (end[0])
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
if (!str[0])
|
||||
return FALSE;
|
||||
char *end;
|
||||
*value = strtod(str, &end);
|
||||
if (end[0])
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean read_double_with_percent(const char *str, double *value)
|
||||
{
|
||||
if (!str[0])
|
||||
return FALSE;
|
||||
char *end;
|
||||
*value = strtod(str, &end);
|
||||
if (end[0] == '%' && !end[1]) {
|
||||
*value *= 0.01;
|
||||
return TRUE;
|
||||
}
|
||||
if (end[0])
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
if (!str[0])
|
||||
return FALSE;
|
||||
char *end;
|
||||
*value = strtod(str, &end);
|
||||
if (end[0] == '%' && !end[1]) {
|
||||
*value *= 0.01;
|
||||
return TRUE;
|
||||
}
|
||||
if (end[0])
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GradientType gradient_type_from_string(const char *str)
|
||||
{
|
||||
if (g_str_equal(str, "horizontal"))
|
||||
return GRADIENT_HORIZONTAL;
|
||||
if (g_str_equal(str, "vertical"))
|
||||
return GRADIENT_VERTICAL;
|
||||
if (g_str_equal(str, "radial"))
|
||||
return GRADIENT_CENTERED;
|
||||
fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str);
|
||||
return GRADIENT_VERTICAL;
|
||||
if (g_str_equal(str, "horizontal"))
|
||||
return GRADIENT_HORIZONTAL;
|
||||
if (g_str_equal(str, "vertical"))
|
||||
return GRADIENT_VERTICAL;
|
||||
if (g_str_equal(str, "radial"))
|
||||
return GRADIENT_CENTERED;
|
||||
fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str);
|
||||
return GRADIENT_VERTICAL;
|
||||
}
|
||||
|
||||
void init_gradient(GradientClass *g, GradientType type)
|
||||
{
|
||||
memset(g, 0, sizeof(*g));
|
||||
g->type = type;
|
||||
if (g->type == GRADIENT_VERTICAL) {
|
||||
Offset *offset_top = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_top->constant = TRUE;
|
||||
offset_top->constant_value = 0;
|
||||
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_top);
|
||||
Offset *offset_bottom = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_bottom->constant = FALSE;
|
||||
offset_bottom->element = ELEMENT_SELF;
|
||||
offset_bottom->variable = SIZE_HEIGHT;
|
||||
offset_bottom->multiplier = 1.0;
|
||||
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_bottom);
|
||||
} else if (g->type == GRADIENT_HORIZONTAL) {
|
||||
Offset *offset_left = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_left->constant = TRUE;
|
||||
offset_left->constant_value = 0;
|
||||
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_left);
|
||||
Offset *offset_right = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_right->constant = FALSE;
|
||||
offset_right->element = ELEMENT_SELF;
|
||||
offset_right->variable = SIZE_WIDTH;
|
||||
offset_right->multiplier = 1.0;
|
||||
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_right);
|
||||
} else if (g->type == GRADIENT_CENTERED) {
|
||||
// from
|
||||
Offset *offset_center_x = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_x->constant = FALSE;
|
||||
offset_center_x->element = ELEMENT_SELF;
|
||||
offset_center_x->variable = SIZE_CENTERX;
|
||||
offset_center_x->multiplier = 1.0;
|
||||
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_center_x);
|
||||
Offset *offset_center_y = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_y->constant = FALSE;
|
||||
offset_center_y->element = ELEMENT_SELF;
|
||||
offset_center_y->variable = SIZE_CENTERY;
|
||||
offset_center_y->multiplier = 1.0;
|
||||
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_center_y);
|
||||
Offset *offset_center_r = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_r->constant = TRUE;
|
||||
offset_center_r->constant_value = 0;
|
||||
g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r);
|
||||
// to
|
||||
offset_center_x = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_x->constant = FALSE;
|
||||
offset_center_x->element = ELEMENT_SELF;
|
||||
offset_center_x->variable = SIZE_CENTERX;
|
||||
offset_center_x->multiplier = 1.0;
|
||||
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_center_x);
|
||||
offset_center_y = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_y->constant = FALSE;
|
||||
offset_center_y->element = ELEMENT_SELF;
|
||||
offset_center_y->variable = SIZE_CENTERY;
|
||||
offset_center_y->multiplier = 1.0;
|
||||
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_center_y);
|
||||
offset_center_r = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_r->constant = FALSE;
|
||||
offset_center_r->element = ELEMENT_SELF;
|
||||
offset_center_r->variable = SIZE_RADIUS;
|
||||
offset_center_r->multiplier = 1.0;
|
||||
g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r);
|
||||
}
|
||||
memset(g, 0, sizeof(*g));
|
||||
g->type = type;
|
||||
if (g->type == GRADIENT_VERTICAL) {
|
||||
Offset *offset_top = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_top->constant = TRUE;
|
||||
offset_top->constant_value = 0;
|
||||
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_top);
|
||||
Offset *offset_bottom = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_bottom->constant = FALSE;
|
||||
offset_bottom->element = ELEMENT_SELF;
|
||||
offset_bottom->variable = SIZE_HEIGHT;
|
||||
offset_bottom->multiplier = 1.0;
|
||||
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_bottom);
|
||||
} else if (g->type == GRADIENT_HORIZONTAL) {
|
||||
Offset *offset_left = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_left->constant = TRUE;
|
||||
offset_left->constant_value = 0;
|
||||
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_left);
|
||||
Offset *offset_right = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_right->constant = FALSE;
|
||||
offset_right->element = ELEMENT_SELF;
|
||||
offset_right->variable = SIZE_WIDTH;
|
||||
offset_right->multiplier = 1.0;
|
||||
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_right);
|
||||
} else if (g->type == GRADIENT_CENTERED) {
|
||||
// from
|
||||
Offset *offset_center_x = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_x->constant = FALSE;
|
||||
offset_center_x->element = ELEMENT_SELF;
|
||||
offset_center_x->variable = SIZE_CENTERX;
|
||||
offset_center_x->multiplier = 1.0;
|
||||
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_center_x);
|
||||
Offset *offset_center_y = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_y->constant = FALSE;
|
||||
offset_center_y->element = ELEMENT_SELF;
|
||||
offset_center_y->variable = SIZE_CENTERY;
|
||||
offset_center_y->multiplier = 1.0;
|
||||
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_center_y);
|
||||
Offset *offset_center_r = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_r->constant = TRUE;
|
||||
offset_center_r->constant_value = 0;
|
||||
g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r);
|
||||
// to
|
||||
offset_center_x = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_x->constant = FALSE;
|
||||
offset_center_x->element = ELEMENT_SELF;
|
||||
offset_center_x->variable = SIZE_CENTERX;
|
||||
offset_center_x->multiplier = 1.0;
|
||||
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_center_x);
|
||||
offset_center_y = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_y->constant = FALSE;
|
||||
offset_center_y->element = ELEMENT_SELF;
|
||||
offset_center_y->variable = SIZE_CENTERY;
|
||||
offset_center_y->multiplier = 1.0;
|
||||
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_center_y);
|
||||
offset_center_r = (Offset *)calloc(1, sizeof(Offset));
|
||||
offset_center_r->constant = FALSE;
|
||||
offset_center_r->element = ELEMENT_SELF;
|
||||
offset_center_r->variable = SIZE_RADIUS;
|
||||
offset_center_r->multiplier = 1.0;
|
||||
g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_gradient(GradientClass *g)
|
||||
{
|
||||
g_list_free_full(g->extra_color_stops, free);
|
||||
g_list_free_full(g->from.offsets_x, free);
|
||||
g_list_free_full(g->from.offsets_y, free);
|
||||
g_list_free_full(g->from.offsets_r, free);
|
||||
g_list_free_full(g->to.offsets_x, free);
|
||||
g_list_free_full(g->to.offsets_y, free);
|
||||
g_list_free_full(g->to.offsets_r, free);
|
||||
bzero(g, sizeof(*g));
|
||||
g_list_free_full(g->extra_color_stops, free);
|
||||
g_list_free_full(g->from.offsets_x, free);
|
||||
g_list_free_full(g->from.offsets_y, free);
|
||||
g_list_free_full(g->from.offsets_r, free);
|
||||
g_list_free_full(g->to.offsets_x, free);
|
||||
g_list_free_full(g->to.offsets_y, free);
|
||||
g_list_free_full(g->to.offsets_r, free);
|
||||
bzero(g, sizeof(*g));
|
||||
}
|
||||
|
||||
@@ -9,62 +9,54 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Gradient types read from config options, not associated to any area
|
||||
|
||||
typedef enum GradientType {
|
||||
GRADIENT_VERTICAL = 0,
|
||||
GRADIENT_HORIZONTAL,
|
||||
GRADIENT_CENTERED
|
||||
} GradientType;
|
||||
typedef enum GradientType { GRADIENT_VERTICAL = 0, GRADIENT_HORIZONTAL, GRADIENT_CENTERED } GradientType;
|
||||
|
||||
typedef struct ColorStop {
|
||||
Color color;
|
||||
// offset in 0-1
|
||||
double offset;
|
||||
Color color;
|
||||
// offset in 0-1
|
||||
double offset;
|
||||
} ColorStop;
|
||||
|
||||
typedef enum Element {
|
||||
ELEMENT_SELF = 0,
|
||||
ELEMENT_PARENT,
|
||||
ELEMENT_PANEL
|
||||
} Element;
|
||||
typedef enum Element { ELEMENT_SELF = 0, ELEMENT_PARENT, ELEMENT_PANEL } Element;
|
||||
|
||||
typedef enum SizeVariable {
|
||||
SIZE_WIDTH = 0,
|
||||
SIZE_HEIGHT,
|
||||
SIZE_RADIUS,
|
||||
SIZE_LEFT,
|
||||
SIZE_RIGHT,
|
||||
SIZE_TOP,
|
||||
SIZE_BOTTOM,
|
||||
SIZE_CENTERX,
|
||||
SIZE_CENTERY
|
||||
SIZE_WIDTH = 0,
|
||||
SIZE_HEIGHT,
|
||||
SIZE_RADIUS,
|
||||
SIZE_LEFT,
|
||||
SIZE_RIGHT,
|
||||
SIZE_TOP,
|
||||
SIZE_BOTTOM,
|
||||
SIZE_CENTERX,
|
||||
SIZE_CENTERY
|
||||
} SizeVariable;
|
||||
|
||||
typedef struct Offset {
|
||||
gboolean constant;
|
||||
// if constant == true
|
||||
double constant_value;
|
||||
// else
|
||||
Element element;
|
||||
SizeVariable variable;
|
||||
double multiplier;
|
||||
gboolean constant;
|
||||
// if constant == true
|
||||
double constant_value;
|
||||
// else
|
||||
Element element;
|
||||
SizeVariable variable;
|
||||
double multiplier;
|
||||
} Offset;
|
||||
|
||||
typedef struct ControlPoint {
|
||||
// Each element is an Offset
|
||||
GList *offsets_x;
|
||||
GList *offsets_y;
|
||||
// Defined only for radial gradients
|
||||
GList *offsets_r;
|
||||
// Each element is an Offset
|
||||
GList *offsets_x;
|
||||
GList *offsets_y;
|
||||
// Defined only for radial gradients
|
||||
GList *offsets_r;
|
||||
} ControlPoint;
|
||||
|
||||
typedef struct GradientClass {
|
||||
GradientType type;
|
||||
Color start_color;
|
||||
Color end_color;
|
||||
// Each element is a ColorStop
|
||||
GList *extra_color_stops;
|
||||
ControlPoint from;
|
||||
ControlPoint to;
|
||||
GradientType type;
|
||||
Color start_color;
|
||||
Color end_color;
|
||||
// Each element is a ColorStop
|
||||
GList *extra_color_stops;
|
||||
ControlPoint from;
|
||||
ControlPoint to;
|
||||
} GradientClass;
|
||||
|
||||
GradientType gradient_type_from_string(const char *str);
|
||||
@@ -78,9 +70,9 @@ struct Area;
|
||||
typedef struct Area Area;
|
||||
|
||||
typedef struct GradientInstance {
|
||||
GradientClass *gradient_class;
|
||||
Area *area;
|
||||
cairo_pattern_t *pattern;
|
||||
GradientClass *gradient_class;
|
||||
Area *area;
|
||||
cairo_pattern_t *pattern;
|
||||
} GradientInstance;
|
||||
|
||||
extern gboolean debug_gradients;
|
||||
|
||||
@@ -43,110 +43,110 @@
|
||||
// remember it in BIAS.
|
||||
static int compare_right(char const *a, char const *b)
|
||||
{
|
||||
int bias = 0;
|
||||
int bias = 0;
|
||||
|
||||
for (;; a++, b++) {
|
||||
if (!isdigit(*a) && !isdigit(*b))
|
||||
return bias;
|
||||
else if (!isdigit(*a))
|
||||
return -1;
|
||||
else if (!isdigit(*b))
|
||||
return +1;
|
||||
else if (*a < *b) {
|
||||
if (!bias)
|
||||
bias = -1;
|
||||
} else if (*a > *b) {
|
||||
if (!bias)
|
||||
bias = +1;
|
||||
} else if (!*a && !*b)
|
||||
return bias;
|
||||
}
|
||||
for (;; a++, b++) {
|
||||
if (!isdigit(*a) && !isdigit(*b))
|
||||
return bias;
|
||||
else if (!isdigit(*a))
|
||||
return -1;
|
||||
else if (!isdigit(*b))
|
||||
return +1;
|
||||
else if (*a < *b) {
|
||||
if (!bias)
|
||||
bias = -1;
|
||||
} else if (*a > *b) {
|
||||
if (!bias)
|
||||
bias = +1;
|
||||
} else if (!*a && !*b)
|
||||
return bias;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compare two left-aligned numbers:
|
||||
// The first to have a different value wins.
|
||||
static int compare_left(char const *a, char const *b)
|
||||
{
|
||||
for (;; a++, b++) {
|
||||
if (!isdigit(*a) && !isdigit(*b))
|
||||
return 0;
|
||||
else if (!isdigit(*a))
|
||||
return -1;
|
||||
else if (!isdigit(*b))
|
||||
return +1;
|
||||
else if (*a < *b)
|
||||
return -1;
|
||||
else if (*a > *b)
|
||||
return +1;
|
||||
}
|
||||
for (;; a++, b++) {
|
||||
if (!isdigit(*a) && !isdigit(*b))
|
||||
return 0;
|
||||
else if (!isdigit(*a))
|
||||
return -1;
|
||||
else if (!isdigit(*b))
|
||||
return +1;
|
||||
else if (*a < *b)
|
||||
return -1;
|
||||
else if (*a > *b)
|
||||
return +1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int strnatcmp0(char const *a, char const *b, int ignore_case)
|
||||
{
|
||||
assert(a && b);
|
||||
assert(a && b);
|
||||
|
||||
int ai, bi;
|
||||
ai = bi = 0;
|
||||
while (1) {
|
||||
char ca = a[ai];
|
||||
char cb = b[bi];
|
||||
int ai, bi;
|
||||
ai = bi = 0;
|
||||
while (1) {
|
||||
char ca = a[ai];
|
||||
char cb = b[bi];
|
||||
|
||||
// Skip over leading spaces
|
||||
while (isspace(ca)) {
|
||||
ai++;
|
||||
ca = a[ai];
|
||||
}
|
||||
// Skip over leading spaces
|
||||
while (isspace(ca)) {
|
||||
ai++;
|
||||
ca = a[ai];
|
||||
}
|
||||
|
||||
while (isspace(cb)) {
|
||||
bi++;
|
||||
cb = b[bi];
|
||||
}
|
||||
while (isspace(cb)) {
|
||||
bi++;
|
||||
cb = b[bi];
|
||||
}
|
||||
|
||||
// Process run of digits
|
||||
if (isdigit(ca) && isdigit(cb)) {
|
||||
int fractional = (ca == '0' || cb == '0');
|
||||
// Process run of digits
|
||||
if (isdigit(ca) && isdigit(cb)) {
|
||||
int fractional = (ca == '0' || cb == '0');
|
||||
|
||||
if (fractional) {
|
||||
int result = compare_left(a + ai, b + bi);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
int result = compare_right(a + ai, b + bi);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (fractional) {
|
||||
int result = compare_left(a + ai, b + bi);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
int result = compare_right(a + ai, b + bi);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ca && !cb) {
|
||||
// The strings compare the same. Perhaps the caller will want to call strcmp to break the tie.
|
||||
return 0;
|
||||
}
|
||||
if (!ca && !cb) {
|
||||
// The strings compare the same. Perhaps the caller will want to call strcmp to break the tie.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ignore_case) {
|
||||
ca = toupper(ca);
|
||||
cb = toupper(cb);
|
||||
}
|
||||
if (ignore_case) {
|
||||
ca = toupper(ca);
|
||||
cb = toupper(cb);
|
||||
}
|
||||
|
||||
if (ca < cb)
|
||||
return -1;
|
||||
else if (ca > cb)
|
||||
return +1;
|
||||
if (ca < cb)
|
||||
return -1;
|
||||
else if (ca > cb)
|
||||
return +1;
|
||||
|
||||
ai++;
|
||||
bi++;
|
||||
}
|
||||
ai++;
|
||||
bi++;
|
||||
}
|
||||
}
|
||||
|
||||
int strnatcmp(char const *a, char const *b)
|
||||
{
|
||||
return strnatcmp0(a, b, 0);
|
||||
return strnatcmp0(a, b, 0);
|
||||
}
|
||||
|
||||
int strnatcasecmp(char const *a, char const *b)
|
||||
{
|
||||
return strnatcmp0(a, b, 1);
|
||||
return strnatcmp0(a, b, 1);
|
||||
}
|
||||
|
||||
566
src/util/timer.c
566
src/util/timer.c
@@ -28,22 +28,22 @@ GHashTable *multi_timeouts;
|
||||
|
||||
// functions and structs for multi timeouts
|
||||
typedef struct {
|
||||
int current_count;
|
||||
int count_to_expiration;
|
||||
int current_count;
|
||||
int count_to_expiration;
|
||||
} multi_timeout;
|
||||
|
||||
typedef struct {
|
||||
GSList *timeout_list;
|
||||
timeout *parent_timeout;
|
||||
GSList *timeout_list;
|
||||
timeout *parent_timeout;
|
||||
} multi_timeout_handler;
|
||||
|
||||
struct _timeout {
|
||||
int interval_msec;
|
||||
struct timespec timeout_expires;
|
||||
void (*_callback)(void *);
|
||||
void *arg;
|
||||
multi_timeout *multi_timeout;
|
||||
timeout **self;
|
||||
int interval_msec;
|
||||
struct timespec timeout_expires;
|
||||
void (*_callback)(void *);
|
||||
void *arg;
|
||||
multi_timeout *multi_timeout;
|
||||
timeout **self;
|
||||
};
|
||||
|
||||
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t);
|
||||
@@ -61,25 +61,25 @@ void stop_multi_timeout(timeout *t);
|
||||
|
||||
void default_timeout()
|
||||
{
|
||||
timeout_list = NULL;
|
||||
multi_timeouts = NULL;
|
||||
timeout_list = NULL;
|
||||
multi_timeouts = NULL;
|
||||
}
|
||||
|
||||
void cleanup_timeout()
|
||||
{
|
||||
while (timeout_list) {
|
||||
timeout *t = timeout_list->data;
|
||||
if (t->multi_timeout)
|
||||
stop_multi_timeout(t);
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
}
|
||||
if (multi_timeouts) {
|
||||
g_hash_table_destroy(multi_timeouts);
|
||||
multi_timeouts = NULL;
|
||||
}
|
||||
while (timeout_list) {
|
||||
timeout *t = timeout_list->data;
|
||||
if (t->multi_timeout)
|
||||
stop_multi_timeout(t);
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
}
|
||||
if (multi_timeouts) {
|
||||
g_hash_table_destroy(multi_timeouts);
|
||||
multi_timeouts = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation notes for timeouts
|
||||
@@ -96,358 +96,358 @@ void cleanup_timeout()
|
||||
|
||||
timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self)
|
||||
{
|
||||
if (self && *self)
|
||||
return *self;
|
||||
timeout *t = calloc(1, sizeof(timeout));
|
||||
t->self = self;
|
||||
add_timeout_intern(value_msec, interval_msec, _callback, arg, t);
|
||||
return t;
|
||||
if (self && *self)
|
||||
return *self;
|
||||
timeout *t = calloc(1, sizeof(timeout));
|
||||
t->self = self;
|
||||
add_timeout_intern(value_msec, interval_msec, _callback, arg, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(), void *arg)
|
||||
{
|
||||
if (!((timeout_list && g_slist_find(timeout_list, *t)) ||
|
||||
(multi_timeouts && g_hash_table_lookup(multi_timeouts, *t))))
|
||||
*t = add_timeout(value_msec, interval_msec, _callback, arg, t);
|
||||
else {
|
||||
if ((*t)->multi_timeout)
|
||||
remove_from_multi_timeout(*t);
|
||||
else
|
||||
timeout_list = g_slist_remove(timeout_list, *t);
|
||||
add_timeout_intern(value_msec, interval_msec, _callback, arg, *t);
|
||||
}
|
||||
if (!((timeout_list && g_slist_find(timeout_list, *t)) ||
|
||||
(multi_timeouts && g_hash_table_lookup(multi_timeouts, *t))))
|
||||
*t = add_timeout(value_msec, interval_msec, _callback, arg, t);
|
||||
else {
|
||||
if ((*t)->multi_timeout)
|
||||
remove_from_multi_timeout(*t);
|
||||
else
|
||||
timeout_list = g_slist_remove(timeout_list, *t);
|
||||
add_timeout_intern(value_msec, interval_msec, _callback, arg, *t);
|
||||
}
|
||||
}
|
||||
|
||||
void update_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);
|
||||
if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) {
|
||||
next_timeout.tv_sec = 0;
|
||||
next_timeout.tv_usec = 0;
|
||||
} else {
|
||||
next_timeout.tv_sec = next_timeout2.tv_sec;
|
||||
next_timeout.tv_usec = next_timeout2.tv_nsec / 1000;
|
||||
}
|
||||
} else
|
||||
next_timeout.tv_sec = -1;
|
||||
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);
|
||||
if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) {
|
||||
next_timeout.tv_sec = 0;
|
||||
next_timeout.tv_usec = 0;
|
||||
} else {
|
||||
next_timeout.tv_sec = next_timeout2.tv_sec;
|
||||
next_timeout.tv_usec = next_timeout2.tv_nsec / 1000;
|
||||
}
|
||||
} else
|
||||
next_timeout.tv_sec = -1;
|
||||
}
|
||||
|
||||
void callback_timeout_expired()
|
||||
{
|
||||
struct timespec cur_time;
|
||||
timeout *t;
|
||||
while (timeout_list) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
t = timeout_list->data;
|
||||
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
|
||||
// it's time for the callback function
|
||||
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)) {
|
||||
// Timer still exists
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
if (t->interval_msec > 0) {
|
||||
add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t);
|
||||
} else {
|
||||
// Destroy single-shot timer
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
struct timespec cur_time;
|
||||
timeout *t;
|
||||
while (timeout_list) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
t = timeout_list->data;
|
||||
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
|
||||
// it's time for the callback function
|
||||
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)) {
|
||||
// Timer still exists
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
if (t->interval_msec > 0) {
|
||||
add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t);
|
||||
} else {
|
||||
// Destroy single-shot timer
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop_timeout(timeout *t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
// if not in the list, it was deleted in callback_timeout_expired
|
||||
if ((timeout_list && g_slist_find(timeout_list, t)) || (multi_timeouts && g_hash_table_lookup(multi_timeouts, t))) {
|
||||
if (multi_timeouts && t->multi_timeout)
|
||||
remove_from_multi_timeout(t);
|
||||
if (timeout_list)
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
}
|
||||
if (!t)
|
||||
return;
|
||||
// if not in the list, it was deleted in callback_timeout_expired
|
||||
if ((timeout_list && g_slist_find(timeout_list, t)) || (multi_timeouts && g_hash_table_lookup(multi_timeouts, t))) {
|
||||
if (multi_timeouts && t->multi_timeout)
|
||||
remove_from_multi_timeout(t);
|
||||
if (timeout_list)
|
||||
timeout_list = g_slist_remove(timeout_list, t);
|
||||
if (t->self)
|
||||
*t->self = NULL;
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(), void *arg, timeout *t)
|
||||
{
|
||||
t->interval_msec = interval_msec;
|
||||
t->_callback = _callback;
|
||||
t->arg = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
t->timeout_expires = add_msec_to_timespec(cur_time, value_msec);
|
||||
t->interval_msec = interval_msec;
|
||||
t->_callback = _callback;
|
||||
t->arg = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
t->timeout_expires = add_msec_to_timespec(cur_time, value_msec);
|
||||
|
||||
int can_align = 0;
|
||||
if (interval_msec > 0 && !t->multi_timeout)
|
||||
can_align = align_with_existing_timeouts(t);
|
||||
if (!can_align)
|
||||
timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
|
||||
int can_align = 0;
|
||||
if (interval_msec > 0 && !t->multi_timeout)
|
||||
can_align = align_with_existing_timeouts(t);
|
||||
if (!can_align)
|
||||
timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
|
||||
}
|
||||
|
||||
gint compare_timeouts(gconstpointer t1, gconstpointer t2)
|
||||
{
|
||||
return compare_timespecs(&((const timeout *)t1)->timeout_expires, &((const timeout *)t2)->timeout_expires);
|
||||
return compare_timespecs(&((const timeout *)t1)->timeout_expires, &((const timeout *)t2)->timeout_expires);
|
||||
}
|
||||
|
||||
gint compare_timespecs(const struct timespec *t1, const struct timespec *t2)
|
||||
{
|
||||
if (t1->tv_sec < t2->tv_sec)
|
||||
return -1;
|
||||
else if (t1->tv_sec == t2->tv_sec) {
|
||||
if (t1->tv_nsec < t2->tv_nsec)
|
||||
return -1;
|
||||
else if (t1->tv_nsec == t2->tv_nsec)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
} else
|
||||
return 1;
|
||||
if (t1->tv_sec < t2->tv_sec)
|
||||
return -1;
|
||||
else if (t1->tv_sec == t2->tv_sec) {
|
||||
if (t1->tv_nsec < t2->tv_nsec)
|
||||
return -1;
|
||||
else if (t1->tv_nsec == t2->tv_nsec)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
|
||||
{
|
||||
/* Perform the carry for the later subtraction by updating y. */
|
||||
if (x->tv_nsec < y->tv_nsec) {
|
||||
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
|
||||
y->tv_nsec -= 1000000000 * nsec;
|
||||
y->tv_sec += nsec;
|
||||
}
|
||||
if (x->tv_nsec - y->tv_nsec > 1000000000) {
|
||||
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
|
||||
y->tv_nsec += 1000000000 * nsec;
|
||||
y->tv_sec -= nsec;
|
||||
}
|
||||
/* Perform the carry for the later subtraction by updating y. */
|
||||
if (x->tv_nsec < y->tv_nsec) {
|
||||
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
|
||||
y->tv_nsec -= 1000000000 * nsec;
|
||||
y->tv_sec += nsec;
|
||||
}
|
||||
if (x->tv_nsec - y->tv_nsec > 1000000000) {
|
||||
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
|
||||
y->tv_nsec += 1000000000 * nsec;
|
||||
y->tv_sec -= nsec;
|
||||
}
|
||||
|
||||
/* Compute the time remaining to wait. tv_nsec is certainly positive. */
|
||||
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||
result->tv_nsec = x->tv_nsec - y->tv_nsec;
|
||||
/* Compute the time remaining to wait. tv_nsec is certainly positive. */
|
||||
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||
result->tv_nsec = x->tv_nsec - y->tv_nsec;
|
||||
|
||||
/* Return 1 if result is negative. */
|
||||
return x->tv_sec < y->tv_sec;
|
||||
/* Return 1 if result is negative. */
|
||||
return x->tv_sec < y->tv_sec;
|
||||
}
|
||||
|
||||
struct timespec add_msec_to_timespec(struct timespec ts, int msec)
|
||||
{
|
||||
ts.tv_sec += msec / 1000;
|
||||
ts.tv_nsec += (msec % 1000) * 1000000;
|
||||
if (ts.tv_nsec >= 1000000000) { // 10^9
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
return ts;
|
||||
ts.tv_sec += msec / 1000;
|
||||
ts.tv_nsec += (msec % 1000) * 1000000;
|
||||
if (ts.tv_nsec >= 1000000000) { // 10^9
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
int align_with_existing_timeouts(timeout *t)
|
||||
{
|
||||
GSList *it = timeout_list;
|
||||
while (it) {
|
||||
timeout *t2 = it->data;
|
||||
if (t2->interval_msec > 0) {
|
||||
if (t->interval_msec % t2->interval_msec == 0 || t2->interval_msec % t->interval_msec == 0) {
|
||||
if (!multi_timeouts)
|
||||
multi_timeouts = g_hash_table_new(0, 0);
|
||||
if (!t->multi_timeout && !t2->multi_timeout) {
|
||||
// both timeouts can be aligned, but there is no multi timeout for them
|
||||
create_multi_timeout(t, t2);
|
||||
} else {
|
||||
// there is already a multi timeout, so we append the new timeout to the multi timeout
|
||||
append_multi_timeout(t, t2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
it = it->next;
|
||||
}
|
||||
return 0;
|
||||
GSList *it = timeout_list;
|
||||
while (it) {
|
||||
timeout *t2 = it->data;
|
||||
if (t2->interval_msec > 0) {
|
||||
if (t->interval_msec % t2->interval_msec == 0 || t2->interval_msec % t->interval_msec == 0) {
|
||||
if (!multi_timeouts)
|
||||
multi_timeouts = g_hash_table_new(0, 0);
|
||||
if (!t->multi_timeout && !t2->multi_timeout) {
|
||||
// both timeouts can be aligned, but there is no multi timeout for them
|
||||
create_multi_timeout(t, t2);
|
||||
} else {
|
||||
// there is already a multi timeout, so we append the new timeout to the multi timeout
|
||||
append_multi_timeout(t, t2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
it = it->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int calc_multi_timeout_interval(multi_timeout_handler *mth)
|
||||
{
|
||||
GSList *it = mth->timeout_list;
|
||||
timeout *t = it->data;
|
||||
int min_interval = t->interval_msec;
|
||||
it = it->next;
|
||||
while (it) {
|
||||
t = it->data;
|
||||
if (t->interval_msec < min_interval)
|
||||
min_interval = t->interval_msec;
|
||||
it = it->next;
|
||||
}
|
||||
return min_interval;
|
||||
GSList *it = mth->timeout_list;
|
||||
timeout *t = it->data;
|
||||
int min_interval = t->interval_msec;
|
||||
it = it->next;
|
||||
while (it) {
|
||||
t = it->data;
|
||||
if (t->interval_msec < min_interval)
|
||||
min_interval = t->interval_msec;
|
||||
it = it->next;
|
||||
}
|
||||
return min_interval;
|
||||
}
|
||||
|
||||
void create_multi_timeout(timeout *t1, timeout *t2)
|
||||
{
|
||||
multi_timeout *mt1 = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout *mt2 = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout_handler *mth = calloc(1, sizeof(multi_timeout_handler));
|
||||
timeout *real_timeout = calloc(1, sizeof(timeout));
|
||||
multi_timeout *mt1 = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout *mt2 = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout_handler *mth = calloc(1, sizeof(multi_timeout_handler));
|
||||
timeout *real_timeout = calloc(1, sizeof(timeout));
|
||||
|
||||
mth->timeout_list = 0;
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t1);
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
|
||||
mth->parent_timeout = real_timeout;
|
||||
mth->timeout_list = 0;
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t1);
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
|
||||
mth->parent_timeout = real_timeout;
|
||||
|
||||
g_hash_table_insert(multi_timeouts, t1, mth);
|
||||
g_hash_table_insert(multi_timeouts, t2, mth);
|
||||
g_hash_table_insert(multi_timeouts, real_timeout, mth);
|
||||
g_hash_table_insert(multi_timeouts, t1, mth);
|
||||
g_hash_table_insert(multi_timeouts, t2, mth);
|
||||
g_hash_table_insert(multi_timeouts, real_timeout, mth);
|
||||
|
||||
t1->multi_timeout = mt1;
|
||||
t2->multi_timeout = mt2;
|
||||
// set real_timeout->multi_timeout to something, such that we see in add_timeout_intern that
|
||||
// it is already a multi_timeout (we never use it, except of checking for 0 ptr)
|
||||
real_timeout->multi_timeout = (void *)real_timeout;
|
||||
t1->multi_timeout = mt1;
|
||||
t2->multi_timeout = mt2;
|
||||
// set real_timeout->multi_timeout to something, such that we see in add_timeout_intern that
|
||||
// it is already a multi_timeout (we never use it, except of checking for 0 ptr)
|
||||
real_timeout->multi_timeout = (void *)real_timeout;
|
||||
|
||||
timeout_list = g_slist_remove(timeout_list, t1);
|
||||
timeout_list = g_slist_remove(timeout_list, t2);
|
||||
timeout_list = g_slist_remove(timeout_list, t1);
|
||||
timeout_list = g_slist_remove(timeout_list, t2);
|
||||
|
||||
update_multi_timeout_values(mth);
|
||||
update_multi_timeout_values(mth);
|
||||
}
|
||||
|
||||
void append_multi_timeout(timeout *t1, timeout *t2)
|
||||
{
|
||||
if (t2->multi_timeout) {
|
||||
// swap t1 and t2 such that t1 is the multi timeout
|
||||
timeout *tmp = t2;
|
||||
t2 = t1;
|
||||
t1 = tmp;
|
||||
}
|
||||
if (t2->multi_timeout) {
|
||||
// swap t1 and t2 such that t1 is the multi timeout
|
||||
timeout *tmp = t2;
|
||||
t2 = t1;
|
||||
t1 = tmp;
|
||||
}
|
||||
|
||||
multi_timeout *mt = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t1);
|
||||
multi_timeout *mt = calloc(1, sizeof(multi_timeout));
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t1);
|
||||
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
|
||||
g_hash_table_insert(multi_timeouts, t2, mth);
|
||||
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
|
||||
g_hash_table_insert(multi_timeouts, t2, mth);
|
||||
|
||||
t2->multi_timeout = mt;
|
||||
t2->multi_timeout = mt;
|
||||
|
||||
update_multi_timeout_values(mth);
|
||||
update_multi_timeout_values(mth);
|
||||
}
|
||||
|
||||
void update_multi_timeout_values(multi_timeout_handler *mth)
|
||||
{
|
||||
int interval = calc_multi_timeout_interval(mth);
|
||||
int next_timeout_msec = interval;
|
||||
int interval = calc_multi_timeout_interval(mth);
|
||||
int next_timeout_msec = interval;
|
||||
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
|
||||
GSList *it = mth->timeout_list;
|
||||
struct timespec diff_time;
|
||||
while (it) {
|
||||
timeout *t = it->data;
|
||||
t->multi_timeout->count_to_expiration = t->interval_msec / interval;
|
||||
timespec_subtract(&diff_time, &t->timeout_expires, &cur_time);
|
||||
int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000;
|
||||
int count_left = msec_to_expiration / interval + (msec_to_expiration % interval != 0);
|
||||
t->multi_timeout->current_count = t->multi_timeout->count_to_expiration - count_left;
|
||||
if (msec_to_expiration < next_timeout_msec)
|
||||
next_timeout_msec = msec_to_expiration;
|
||||
it = it->next;
|
||||
}
|
||||
GSList *it = mth->timeout_list;
|
||||
struct timespec diff_time;
|
||||
while (it) {
|
||||
timeout *t = it->data;
|
||||
t->multi_timeout->count_to_expiration = t->interval_msec / interval;
|
||||
timespec_subtract(&diff_time, &t->timeout_expires, &cur_time);
|
||||
int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000;
|
||||
int count_left = msec_to_expiration / interval + (msec_to_expiration % interval != 0);
|
||||
t->multi_timeout->current_count = t->multi_timeout->count_to_expiration - count_left;
|
||||
if (msec_to_expiration < next_timeout_msec)
|
||||
next_timeout_msec = msec_to_expiration;
|
||||
it = it->next;
|
||||
}
|
||||
|
||||
mth->parent_timeout->interval_msec = interval;
|
||||
timeout_list = g_slist_remove(timeout_list, mth->parent_timeout);
|
||||
add_timeout_intern(next_timeout_msec, interval, callback_multi_timeout, mth, mth->parent_timeout);
|
||||
mth->parent_timeout->interval_msec = interval;
|
||||
timeout_list = g_slist_remove(timeout_list, mth->parent_timeout);
|
||||
add_timeout_intern(next_timeout_msec, interval, callback_multi_timeout, mth, mth->parent_timeout);
|
||||
}
|
||||
|
||||
void callback_multi_timeout(void *arg)
|
||||
{
|
||||
multi_timeout_handler *mth = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
GSList *it = mth->timeout_list;
|
||||
while (it) {
|
||||
timeout *t = it->data;
|
||||
if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) {
|
||||
t->_callback(t->arg);
|
||||
if (multi_timeouts && g_hash_table_lookup(multi_timeouts, t)) {
|
||||
// Timer still exists
|
||||
t->multi_timeout->current_count = 0;
|
||||
t->timeout_expires = add_msec_to_timespec(cur_time, t->interval_msec);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
it = it->next;
|
||||
}
|
||||
multi_timeout_handler *mth = arg;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
GSList *it = mth->timeout_list;
|
||||
while (it) {
|
||||
timeout *t = it->data;
|
||||
if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) {
|
||||
t->_callback(t->arg);
|
||||
if (multi_timeouts && g_hash_table_lookup(multi_timeouts, t)) {
|
||||
// Timer still exists
|
||||
t->multi_timeout->current_count = 0;
|
||||
t->timeout_expires = add_msec_to_timespec(cur_time, t->interval_msec);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
it = it->next;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_from_multi_timeout(timeout *t)
|
||||
{
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
|
||||
g_hash_table_remove(multi_timeouts, t);
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
|
||||
g_hash_table_remove(multi_timeouts, t);
|
||||
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, t);
|
||||
free(t->multi_timeout);
|
||||
t->multi_timeout = 0;
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, t);
|
||||
free(t->multi_timeout);
|
||||
t->multi_timeout = 0;
|
||||
|
||||
if (g_slist_length(mth->timeout_list) == 1) {
|
||||
timeout *last_timeout = mth->timeout_list->data;
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, last_timeout);
|
||||
free(last_timeout->multi_timeout);
|
||||
last_timeout->multi_timeout = 0;
|
||||
g_hash_table_remove(multi_timeouts, last_timeout);
|
||||
g_hash_table_remove(multi_timeouts, mth->parent_timeout);
|
||||
mth->parent_timeout->multi_timeout = 0;
|
||||
stop_timeout(mth->parent_timeout);
|
||||
free(mth);
|
||||
if (g_slist_length(mth->timeout_list) == 1) {
|
||||
timeout *last_timeout = mth->timeout_list->data;
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, last_timeout);
|
||||
free(last_timeout->multi_timeout);
|
||||
last_timeout->multi_timeout = 0;
|
||||
g_hash_table_remove(multi_timeouts, last_timeout);
|
||||
g_hash_table_remove(multi_timeouts, mth->parent_timeout);
|
||||
mth->parent_timeout->multi_timeout = 0;
|
||||
stop_timeout(mth->parent_timeout);
|
||||
free(mth);
|
||||
|
||||
struct timespec cur_time, diff_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &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,
|
||||
last_timeout->interval_msec,
|
||||
last_timeout->_callback,
|
||||
last_timeout->arg,
|
||||
last_timeout);
|
||||
} else
|
||||
update_multi_timeout_values(mth);
|
||||
struct timespec cur_time, diff_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &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,
|
||||
last_timeout->interval_msec,
|
||||
last_timeout->_callback,
|
||||
last_timeout->arg,
|
||||
last_timeout);
|
||||
} else
|
||||
update_multi_timeout_values(mth);
|
||||
}
|
||||
|
||||
void stop_multi_timeout(timeout *t)
|
||||
{
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
|
||||
g_hash_table_remove(multi_timeouts, mth->parent_timeout);
|
||||
while (mth->timeout_list) {
|
||||
timeout *t1 = mth->timeout_list->data;
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, t1);
|
||||
g_hash_table_remove(multi_timeouts, t1);
|
||||
free(t1->multi_timeout);
|
||||
free(t1);
|
||||
}
|
||||
free(mth);
|
||||
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
|
||||
g_hash_table_remove(multi_timeouts, mth->parent_timeout);
|
||||
while (mth->timeout_list) {
|
||||
timeout *t1 = mth->timeout_list->data;
|
||||
mth->timeout_list = g_slist_remove(mth->timeout_list, t1);
|
||||
g_hash_table_remove(multi_timeouts, t1);
|
||||
free(t1->multi_timeout);
|
||||
free(t1);
|
||||
}
|
||||
free(mth);
|
||||
}
|
||||
|
||||
double profiling_get_time_old_time = 0;
|
||||
|
||||
double get_time()
|
||||
{
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
|
||||
struct timespec cur_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
|
||||
}
|
||||
|
||||
double profiling_get_time()
|
||||
{
|
||||
double t = get_time();
|
||||
if (profiling_get_time_old_time == 0)
|
||||
profiling_get_time_old_time = t;
|
||||
double delta = t - profiling_get_time_old_time;
|
||||
profiling_get_time_old_time = t;
|
||||
return delta;
|
||||
double t = get_time();
|
||||
if (profiling_get_time_old_time == 0)
|
||||
profiling_get_time_old_time = t;
|
||||
double delta = t - profiling_get_time_old_time;
|
||||
profiling_get_time_old_time = t;
|
||||
return delta;
|
||||
}
|
||||
|
||||
@@ -38,170 +38,170 @@ static GList *notifiers = NULL;
|
||||
|
||||
static const char *has_prefix(const char *str, const char *end, const char *prefix, size_t prefixlen)
|
||||
{
|
||||
if ((end - str) < prefixlen)
|
||||
return NULL;
|
||||
if ((end - str) < prefixlen)
|
||||
return NULL;
|
||||
|
||||
if (!memcmp(str, prefix, prefixlen))
|
||||
return str + prefixlen;
|
||||
if (!memcmp(str, prefix, prefixlen))
|
||||
return str + prefixlen;
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define HAS_CONST_PREFIX(str, end, prefix) has_prefix((str), end, prefix, sizeof(prefix) - 1)
|
||||
|
||||
static void uevent_param_free(gpointer data)
|
||||
{
|
||||
struct uevent_parameter *param = data;
|
||||
free(param->key);
|
||||
free(param->val);
|
||||
free(param);
|
||||
struct uevent_parameter *param = data;
|
||||
free(param->key);
|
||||
free(param->val);
|
||||
free(param);
|
||||
}
|
||||
|
||||
static void uevent_free(struct uevent *ev)
|
||||
{
|
||||
free(ev->path);
|
||||
free(ev->subsystem);
|
||||
g_list_free_full(ev->params, uevent_param_free);
|
||||
free(ev);
|
||||
free(ev->path);
|
||||
free(ev->subsystem);
|
||||
g_list_free_full(ev->params, uevent_param_free);
|
||||
free(ev);
|
||||
}
|
||||
|
||||
static struct uevent *uevent_new(char *buffer, int size)
|
||||
{
|
||||
gboolean first = TRUE;
|
||||
gboolean first = TRUE;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
struct uevent *ev = calloc(1, sizeof(*ev));
|
||||
if (!ev)
|
||||
return NULL;
|
||||
struct uevent *ev = calloc(1, sizeof(*ev));
|
||||
if (!ev)
|
||||
return NULL;
|
||||
|
||||
/* ensure nul termination required by strlen() */
|
||||
buffer[size - 1] = '\0';
|
||||
/* ensure nul termination required by strlen() */
|
||||
buffer[size - 1] = '\0';
|
||||
|
||||
const char *s = buffer;
|
||||
const char *end = s + size;
|
||||
for (; s < end; s += strlen(s) + 1) {
|
||||
if (first) {
|
||||
const char *p = strchr(s, '@');
|
||||
if (!p) {
|
||||
/* error: kernel events contain @ */
|
||||
/* triggered by udev events, though */
|
||||
free(ev);
|
||||
return NULL;
|
||||
}
|
||||
ev->path = strdup(p + 1);
|
||||
first = FALSE;
|
||||
} else {
|
||||
const char *val;
|
||||
if ((val = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
|
||||
if (!strcmp(val, "add"))
|
||||
ev->action = UEVENT_ADD;
|
||||
else if (!strcmp(val, "remove"))
|
||||
ev->action = UEVENT_REMOVE;
|
||||
else if (!strcmp(val, "change"))
|
||||
ev->action = UEVENT_CHANGE;
|
||||
else
|
||||
ev->action = UEVENT_UNKNOWN;
|
||||
} else if ((val = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
|
||||
ev->sequence = atoi(val);
|
||||
} else if ((val = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
|
||||
ev->subsystem = strdup(val);
|
||||
} else {
|
||||
val = strchr(s, '=');
|
||||
if (val) {
|
||||
struct uevent_parameter *param = malloc(sizeof(*param));
|
||||
if (param) {
|
||||
param->key = strndup(s, val - s);
|
||||
param->val = strdup(val + 1);
|
||||
ev->params = g_list_append(ev->params, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const char *s = buffer;
|
||||
const char *end = s + size;
|
||||
for (; s < end; s += strlen(s) + 1) {
|
||||
if (first) {
|
||||
const char *p = strchr(s, '@');
|
||||
if (!p) {
|
||||
/* error: kernel events contain @ */
|
||||
/* triggered by udev events, though */
|
||||
free(ev);
|
||||
return NULL;
|
||||
}
|
||||
ev->path = strdup(p + 1);
|
||||
first = FALSE;
|
||||
} else {
|
||||
const char *val;
|
||||
if ((val = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
|
||||
if (!strcmp(val, "add"))
|
||||
ev->action = UEVENT_ADD;
|
||||
else if (!strcmp(val, "remove"))
|
||||
ev->action = UEVENT_REMOVE;
|
||||
else if (!strcmp(val, "change"))
|
||||
ev->action = UEVENT_CHANGE;
|
||||
else
|
||||
ev->action = UEVENT_UNKNOWN;
|
||||
} else if ((val = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
|
||||
ev->sequence = atoi(val);
|
||||
} else if ((val = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
|
||||
ev->subsystem = strdup(val);
|
||||
} else {
|
||||
val = strchr(s, '=');
|
||||
if (val) {
|
||||
struct uevent_parameter *param = malloc(sizeof(*param));
|
||||
if (param) {
|
||||
param->key = strndup(s, val - s);
|
||||
param->val = strdup(val + 1);
|
||||
ev->params = g_list_append(ev->params, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ev;
|
||||
return ev;
|
||||
}
|
||||
|
||||
void uevent_register_notifier(struct uevent_notify *nb)
|
||||
{
|
||||
notifiers = g_list_append(notifiers, nb);
|
||||
notifiers = g_list_append(notifiers, nb);
|
||||
}
|
||||
|
||||
void uevent_unregister_notifier(struct uevent_notify *nb)
|
||||
{
|
||||
GList *l = notifiers;
|
||||
GList *l = notifiers;
|
||||
|
||||
while (l != NULL) {
|
||||
GList *next = l->next;
|
||||
struct uevent_notify *lnb = l->data;
|
||||
while (l != NULL) {
|
||||
GList *next = l->next;
|
||||
struct uevent_notify *lnb = l->data;
|
||||
|
||||
if (memcmp(nb, lnb, sizeof(struct uevent_notify)) == 0)
|
||||
notifiers = g_list_delete_link(notifiers, l);
|
||||
if (memcmp(nb, lnb, sizeof(struct uevent_notify)) == 0)
|
||||
notifiers = g_list_delete_link(notifiers, l);
|
||||
|
||||
l = next;
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
}
|
||||
|
||||
void uevent_handler()
|
||||
{
|
||||
if (ueventfd < 0)
|
||||
return;
|
||||
if (ueventfd < 0)
|
||||
return;
|
||||
|
||||
char buf[512];
|
||||
int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len < 0)
|
||||
return;
|
||||
char buf[512];
|
||||
int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
struct uevent *ev = uevent_new(buf, len);
|
||||
if (ev) {
|
||||
for (GList *l = notifiers; l; l = l->next) {
|
||||
struct uevent_notify *nb = l->data;
|
||||
struct uevent *ev = uevent_new(buf, len);
|
||||
if (ev) {
|
||||
for (GList *l = notifiers; l; l = l->next) {
|
||||
struct uevent_notify *nb = l->data;
|
||||
|
||||
if (!(ev->action & nb->action))
|
||||
continue;
|
||||
if (!(ev->action & nb->action))
|
||||
continue;
|
||||
|
||||
if (nb->subsystem && strcmp(ev->subsystem, nb->subsystem))
|
||||
continue;
|
||||
if (nb->subsystem && strcmp(ev->subsystem, nb->subsystem))
|
||||
continue;
|
||||
|
||||
nb->cb(ev, nb->userdata);
|
||||
}
|
||||
nb->cb(ev, nb->userdata);
|
||||
}
|
||||
|
||||
uevent_free(ev);
|
||||
}
|
||||
uevent_free(ev);
|
||||
}
|
||||
}
|
||||
|
||||
int uevent_init()
|
||||
{
|
||||
/* Open hotplug event netlink socket */
|
||||
memset(&nls, 0, sizeof(struct sockaddr_nl));
|
||||
nls.nl_family = AF_NETLINK;
|
||||
nls.nl_pid = getpid();
|
||||
nls.nl_groups = -1;
|
||||
/* Open hotplug event netlink socket */
|
||||
memset(&nls, 0, sizeof(struct sockaddr_nl));
|
||||
nls.nl_family = AF_NETLINK;
|
||||
nls.nl_pid = getpid();
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
/* open socket */
|
||||
ueventfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (ueventfd < 0) {
|
||||
fprintf(stderr, "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");
|
||||
return -1;
|
||||
}
|
||||
/* Listen to netlink socket */
|
||||
if (bind(ueventfd, (void *)&nls, sizeof(struct sockaddr_nl))) {
|
||||
fprintf(stderr, "Bind failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Kernel uevent interface initialized...\n");
|
||||
printf("Kernel uevent interface initialized...\n");
|
||||
|
||||
return ueventfd;
|
||||
return ueventfd;
|
||||
}
|
||||
|
||||
void uevent_cleanup()
|
||||
{
|
||||
if (ueventfd >= 0)
|
||||
close(ueventfd);
|
||||
if (ueventfd >= 0)
|
||||
close(ueventfd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,31 +21,31 @@
|
||||
#define UEVENT_H
|
||||
|
||||
enum uevent_action {
|
||||
UEVENT_UNKNOWN = 0x01,
|
||||
UEVENT_ADD = 0x02,
|
||||
UEVENT_REMOVE = 0x04,
|
||||
UEVENT_CHANGE = 0x08,
|
||||
UEVENT_UNKNOWN = 0x01,
|
||||
UEVENT_ADD = 0x02,
|
||||
UEVENT_REMOVE = 0x04,
|
||||
UEVENT_CHANGE = 0x08,
|
||||
};
|
||||
|
||||
struct uevent_parameter {
|
||||
char *key;
|
||||
char *val;
|
||||
char *key;
|
||||
char *val;
|
||||
};
|
||||
|
||||
struct uevent {
|
||||
char *path;
|
||||
enum uevent_action action;
|
||||
int sequence;
|
||||
char *subsystem;
|
||||
GList *params;
|
||||
char *path;
|
||||
enum uevent_action action;
|
||||
int sequence;
|
||||
char *subsystem;
|
||||
GList *params;
|
||||
};
|
||||
|
||||
struct uevent_notify {
|
||||
int action; /* bitfield */
|
||||
char *subsystem; /* NULL => any */
|
||||
void *userdata;
|
||||
int action; /* bitfield */
|
||||
char *subsystem; /* NULL => any */
|
||||
void *userdata;
|
||||
|
||||
void (*cb)(struct uevent *e, void *userdata);
|
||||
void (*cb)(struct uevent *e, void *userdata);
|
||||
};
|
||||
|
||||
#if ENABLE_UEVENT
|
||||
@@ -58,7 +58,7 @@ void uevent_unregister_notifier(struct uevent_notify *nb);
|
||||
#else
|
||||
static inline int uevent_init()
|
||||
{
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void uevent_cleanup()
|
||||
|
||||
@@ -37,288 +37,288 @@
|
||||
|
||||
void activate_window(Window win)
|
||||
{
|
||||
send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0);
|
||||
send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0);
|
||||
}
|
||||
|
||||
void change_window_desktop(Window win, int desktop)
|
||||
{
|
||||
send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0);
|
||||
send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0);
|
||||
}
|
||||
|
||||
void close_window(Window win)
|
||||
{
|
||||
send_event32(win, server.atom._NET_CLOSE_WINDOW, 0, 2, 0);
|
||||
send_event32(win, server.atom._NET_CLOSE_WINDOW, 0, 2, 0);
|
||||
}
|
||||
|
||||
void toggle_window_shade(Window win)
|
||||
{
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_SHADED, 0);
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_SHADED, 0);
|
||||
}
|
||||
|
||||
void toggle_window_maximized(Window win)
|
||||
{
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_VERT, 0);
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_HORZ, 0);
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_VERT, 0);
|
||||
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_HORZ, 0);
|
||||
}
|
||||
|
||||
gboolean window_is_hidden(Window win)
|
||||
{
|
||||
Window window;
|
||||
int count;
|
||||
Window window;
|
||||
int count;
|
||||
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
// do not add transient_for windows if the transient window is already in the taskbar
|
||||
window = win;
|
||||
while (XGetTransientForHint(server.display, window, &window)) {
|
||||
if (get_task_buttons(window)) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
// do not add transient_for windows if the transient window is already in the taskbar
|
||||
window = win;
|
||||
while (XGetTransientForHint(server.display, window, &window)) {
|
||||
if (get_task_buttons(window)) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
|
||||
at = server_get_property(win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_WINDOW_TYPE_DOCK || at[i] == server.atom._NET_WM_WINDOW_TYPE_DESKTOP ||
|
||||
at[i] == server.atom._NET_WM_WINDOW_TYPE_TOOLBAR || at[i] == server.atom._NET_WM_WINDOW_TYPE_MENU ||
|
||||
at[i] == server.atom._NET_WM_WINDOW_TYPE_SPLASH) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
at = server_get_property(win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_WINDOW_TYPE_DOCK || at[i] == server.atom._NET_WM_WINDOW_TYPE_DESKTOP ||
|
||||
at[i] == server.atom._NET_WM_WINDOW_TYPE_TOOLBAR || at[i] == server.atom._NET_WM_WINDOW_TYPE_MENU ||
|
||||
at[i] == server.atom._NET_WM_WINDOW_TYPE_SPLASH) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
if (panels[i].main_win == win) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
if (panels[i].main_win == win) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// specification
|
||||
// Windows with neither _NET_WM_WINDOW_TYPE nor WM_TRANSIENT_FOR set
|
||||
// MUST be taken as top-level window.
|
||||
return FALSE;
|
||||
// specification
|
||||
// Windows with neither _NET_WM_WINDOW_TYPE nor WM_TRANSIENT_FOR set
|
||||
// MUST be taken as top-level window.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int get_window_desktop(Window win)
|
||||
{
|
||||
int desktop = get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
|
||||
if (desktop == ALL_DESKTOPS)
|
||||
return desktop;
|
||||
if (!server.viewports)
|
||||
return CLAMP(desktop, 0, server.num_desktops - 1);
|
||||
int desktop = get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
|
||||
if (desktop == ALL_DESKTOPS)
|
||||
return desktop;
|
||||
if (!server.viewports)
|
||||
return CLAMP(desktop, 0, server.num_desktops - 1);
|
||||
|
||||
int x, y, w, h;
|
||||
get_window_coordinates(win, &x, &y, &w, &h);
|
||||
int x, y, w, h;
|
||||
get_window_coordinates(win, &x, &y, &w, &h);
|
||||
|
||||
desktop = get_current_desktop();
|
||||
// Window coordinates are relative to the current viewport, make them absolute
|
||||
x += server.viewports[desktop].x;
|
||||
y += server.viewports[desktop].y;
|
||||
desktop = get_current_desktop();
|
||||
// Window coordinates are relative to the current viewport, make them absolute
|
||||
x += server.viewports[desktop].x;
|
||||
y += server.viewports[desktop].y;
|
||||
|
||||
if (x < 0 || y < 0) {
|
||||
int num_results;
|
||||
long *x_screen_size =
|
||||
server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
|
||||
if (!x_screen_size)
|
||||
return 0;
|
||||
int x_screen_width = x_screen_size[0];
|
||||
int x_screen_height = x_screen_size[1];
|
||||
XFree(x_screen_size);
|
||||
if (x < 0 || y < 0) {
|
||||
int num_results;
|
||||
long *x_screen_size =
|
||||
server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
|
||||
if (!x_screen_size)
|
||||
return 0;
|
||||
int x_screen_width = x_screen_size[0];
|
||||
int x_screen_height = x_screen_size[1];
|
||||
XFree(x_screen_size);
|
||||
|
||||
// Wrap
|
||||
if (x < 0)
|
||||
x += x_screen_width;
|
||||
if (y < 0)
|
||||
y += x_screen_height;
|
||||
}
|
||||
// Wrap
|
||||
if (x < 0)
|
||||
x += x_screen_width;
|
||||
if (y < 0)
|
||||
y += x_screen_height;
|
||||
}
|
||||
|
||||
int best_match = -1;
|
||||
int match_right = 0;
|
||||
int match_bottom = 0;
|
||||
// There is an ambiguity when a window is right on the edge between viewports.
|
||||
// In that case, prefer the viewports which is on the right and bottom of the window's top-left corner.
|
||||
for (int i = 0; i < server.num_desktops; i++) {
|
||||
if (x >= server.viewports[i].x && x <= (server.viewports[i].x + server.viewports[i].width) &&
|
||||
y >= server.viewports[i].y && y <= (server.viewports[i].y + server.viewports[i].height)) {
|
||||
int current_right = x < (server.viewports[i].x + server.viewports[i].width);
|
||||
int current_bottom = y < (server.viewports[i].y + server.viewports[i].height);
|
||||
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||
best_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
int best_match = -1;
|
||||
int match_right = 0;
|
||||
int match_bottom = 0;
|
||||
// There is an ambiguity when a window is right on the edge between viewports.
|
||||
// In that case, prefer the viewports which is on the right and bottom of the window's top-left corner.
|
||||
for (int i = 0; i < server.num_desktops; i++) {
|
||||
if (x >= server.viewports[i].x && x <= (server.viewports[i].x + server.viewports[i].width) &&
|
||||
y >= server.viewports[i].y && y <= (server.viewports[i].y + server.viewports[i].height)) {
|
||||
int current_right = x < (server.viewports[i].x + server.viewports[i].width);
|
||||
int current_bottom = y < (server.viewports[i].y + server.viewports[i].height);
|
||||
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||
best_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 : "??",
|
||||
// best_match+1, x, y);
|
||||
return best_match;
|
||||
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 : "??",
|
||||
// best_match+1, x, y);
|
||||
return best_match;
|
||||
}
|
||||
|
||||
int get_window_monitor(Window win)
|
||||
{
|
||||
int x, y, w, h;
|
||||
get_window_coordinates(win, &x, &y, &w, &h);
|
||||
int x, y, w, h;
|
||||
get_window_coordinates(win, &x, &y, &w, &h);
|
||||
|
||||
int best_match = -1;
|
||||
int match_right = 0;
|
||||
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++) {
|
||||
if (x >= server.monitors[i].x && x <= (server.monitors[i].x + server.monitors[i].width) &&
|
||||
y >= server.monitors[i].y && y <= (server.monitors[i].y + server.monitors[i].height)) {
|
||||
int current_right = x < (server.monitors[i].x + server.monitors[i].width);
|
||||
int current_bottom = y < (server.monitors[i].y + server.monitors[i].height);
|
||||
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||
best_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
int best_match = -1;
|
||||
int match_right = 0;
|
||||
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++) {
|
||||
if (x >= server.monitors[i].x && x <= (server.monitors[i].x + server.monitors[i].width) &&
|
||||
y >= server.monitors[i].y && y <= (server.monitors[i].y + server.monitors[i].height)) {
|
||||
int current_right = x < (server.monitors[i].x + server.monitors[i].width);
|
||||
int current_bottom = y < (server.monitors[i].y + server.monitors[i].height);
|
||||
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||
best_match = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_match < 0)
|
||||
best_match = 0;
|
||||
// fprintf(stderr, "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;
|
||||
if (best_match < 0)
|
||||
best_match = 0;
|
||||
// fprintf(stderr, "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;
|
||||
}
|
||||
|
||||
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
|
||||
{
|
||||
int dummy_int;
|
||||
unsigned ww, wh, bw, bh;
|
||||
Window src;
|
||||
XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src);
|
||||
XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh);
|
||||
*w = ww + bw;
|
||||
*h = wh + bh;
|
||||
int dummy_int;
|
||||
unsigned ww, wh, bw, bh;
|
||||
Window src;
|
||||
XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src);
|
||||
XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh);
|
||||
*w = ww + bw;
|
||||
*h = wh + bh;
|
||||
}
|
||||
|
||||
gboolean window_is_iconified(Window win)
|
||||
{
|
||||
// EWMH specification : minimization of windows use _NET_WM_STATE_HIDDEN.
|
||||
// WM_STATE is not accurate for shaded window and in multi_desktop mode.
|
||||
int count;
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_HIDDEN) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
// EWMH specification : minimization of windows use _NET_WM_STATE_HIDDEN.
|
||||
// WM_STATE is not accurate for shaded window and in multi_desktop mode.
|
||||
int count;
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_HIDDEN) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean window_is_urgent(Window win)
|
||||
{
|
||||
int count;
|
||||
int count;
|
||||
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_DEMANDS_ATTENTION) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_DEMANDS_ATTENTION) {
|
||||
XFree(at);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean window_is_skip_taskbar(Window win)
|
||||
{
|
||||
int count;
|
||||
int count;
|
||||
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
|
||||
XFree(at);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
|
||||
XFree(at);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
XFree(at);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Window get_active_window()
|
||||
{
|
||||
return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
|
||||
return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
|
||||
}
|
||||
|
||||
gboolean window_is_active(Window win)
|
||||
{
|
||||
return (win == get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW));
|
||||
return (win == get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW));
|
||||
}
|
||||
|
||||
int get_icon_count(gulong *data, int num)
|
||||
{
|
||||
int count, pos, w, h;
|
||||
int count, pos, w, h;
|
||||
|
||||
count = 0;
|
||||
pos = 0;
|
||||
while (pos + 2 < num) {
|
||||
w = data[pos++];
|
||||
h = data[pos++];
|
||||
pos += w * h;
|
||||
if (pos > num || w <= 0 || h <= 0)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
count = 0;
|
||||
pos = 0;
|
||||
while (pos + 2 < num) {
|
||||
w = data[pos++];
|
||||
h = data[pos++];
|
||||
pos += w * h;
|
||||
if (pos > num || w <= 0 || h <= 0)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size)
|
||||
{
|
||||
int width[icon_count], height[icon_count], pos, i, w, h;
|
||||
gulong *icon_data[icon_count];
|
||||
int width[icon_count], height[icon_count], pos, i, w, h;
|
||||
gulong *icon_data[icon_count];
|
||||
|
||||
/* List up icons */
|
||||
pos = 0;
|
||||
i = icon_count;
|
||||
while (i--) {
|
||||
w = data[pos++];
|
||||
h = data[pos++];
|
||||
if (pos + w * h > num)
|
||||
break;
|
||||
/* List up icons */
|
||||
pos = 0;
|
||||
i = icon_count;
|
||||
while (i--) {
|
||||
w = data[pos++];
|
||||
h = data[pos++];
|
||||
if (pos + w * h > num)
|
||||
break;
|
||||
|
||||
width[i] = w;
|
||||
height[i] = h;
|
||||
icon_data[i] = &data[pos];
|
||||
width[i] = w;
|
||||
height[i] = h;
|
||||
icon_data[i] = &data[pos];
|
||||
|
||||
pos += w * h;
|
||||
}
|
||||
pos += w * h;
|
||||
}
|
||||
|
||||
/* Try to find exact size */
|
||||
int icon_num = -1;
|
||||
for (i = 0; i < icon_count; i++) {
|
||||
if (width[i] == best_icon_size) {
|
||||
icon_num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Try to find exact size */
|
||||
int icon_num = -1;
|
||||
for (i = 0; i < icon_count; i++) {
|
||||
if (width[i] == best_icon_size) {
|
||||
icon_num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take the biggest or whatever */
|
||||
if (icon_num < 0) {
|
||||
int highest = 0;
|
||||
for (i = 0; i < icon_count; i++) {
|
||||
if (width[i] > highest) {
|
||||
icon_num = i;
|
||||
highest = width[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Take the biggest or whatever */
|
||||
if (icon_num < 0) {
|
||||
int highest = 0;
|
||||
for (i = 0; i < icon_count; i++) {
|
||||
if (width[i] > highest) {
|
||||
icon_num = i;
|
||||
highest = width[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*iw = width[icon_num];
|
||||
*ih = height[icon_num];
|
||||
return icon_data[icon_num];
|
||||
*iw = width[icon_num];
|
||||
*ih = height[icon_num];
|
||||
return icon_data[icon_num];
|
||||
}
|
||||
|
||||
// Thanks zcodes!
|
||||
|
||||
Reference in New Issue
Block a user