Changed indentation everywhere

This commit is contained in:
o9000
2017-04-13 14:07:23 +02:00
parent c1e5a7b172
commit affac4cfa6
68 changed files with 23280 additions and 22941 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -1,2 +1 @@
#include "color.h"

View File

@@ -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

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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!