Taskbar: thumbnails
This commit is contained in:
parent
8a7e7e4281
commit
5a867a83c6
8 changed files with 109 additions and 14 deletions
|
@ -262,7 +262,7 @@ void handle_event_property_notify(XEvent *e)
|
||||||
if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
|
if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
|
||||||
if (task_update_title(task)) {
|
if (task_update_title(task)) {
|
||||||
if (g_tooltip.mapped && (g_tooltip.area == (Area *)task)) {
|
if (g_tooltip.mapped && (g_tooltip.area == (Area *)task)) {
|
||||||
tooltip_copy_text((Area *)task);
|
tooltip_update_contents_for((Area *)task);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
}
|
}
|
||||||
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
||||||
|
|
|
@ -47,6 +47,12 @@ char *task_get_tooltip(void *obj)
|
||||||
return strdup(t->title);
|
return strdup(t->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cairo_surface_t *task_get_thumbnail(void *obj)
|
||||||
|
{
|
||||||
|
Task *t = (Task *)obj;
|
||||||
|
return t->thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
Task *add_task(Window win)
|
Task *add_task(Window win)
|
||||||
{
|
{
|
||||||
if (!win)
|
if (!win)
|
||||||
|
@ -122,8 +128,10 @@ Task *add_task(Window win)
|
||||||
task_instance->area.on_screen = always_show_all_desktop_tasks;
|
task_instance->area.on_screen = always_show_all_desktop_tasks;
|
||||||
}
|
}
|
||||||
task_instance->title = task_template.title;
|
task_instance->title = task_template.title;
|
||||||
if (panels[monitor].g_task.tooltip_enabled)
|
if (panels[monitor].g_task.tooltip_enabled) {
|
||||||
task_instance->area._get_tooltip_text = task_get_tooltip;
|
task_instance->area._get_tooltip_text = task_get_tooltip;
|
||||||
|
task_instance->area._get_tooltip_image = task_get_thumbnail;
|
||||||
|
}
|
||||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
task_instance->icon[k] = task_template.icon[k];
|
task_instance->icon[k] = task_template.icon[k];
|
||||||
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
||||||
|
@ -201,6 +209,8 @@ void remove_task(Task *task)
|
||||||
// fprintf(stderr, "tint2: remove_task %s %d\n", task->title, task->desktop);
|
// fprintf(stderr, "tint2: remove_task %s %d\n", task->title, task->desktop);
|
||||||
if (task->title)
|
if (task->title)
|
||||||
free(task->title);
|
free(task->title);
|
||||||
|
if (task->thumbnail)
|
||||||
|
cairo_surface_destroy(task->thumbnail);
|
||||||
task_remove_icon(task);
|
task_remove_icon(task);
|
||||||
|
|
||||||
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
||||||
|
@ -212,6 +222,8 @@ void remove_task(Task *task)
|
||||||
task_drag = 0;
|
task_drag = 0;
|
||||||
if (g_slist_find(urgent_list, task2))
|
if (g_slist_find(urgent_list, task2))
|
||||||
del_urgent(task2);
|
del_urgent(task2);
|
||||||
|
if (g_tooltip.area == &task2->area)
|
||||||
|
tooltip_hide(NULL);
|
||||||
remove_area((Area *)task2);
|
remove_area((Area *)task2);
|
||||||
free(task2);
|
free(task2);
|
||||||
}
|
}
|
||||||
|
@ -603,11 +615,25 @@ void reset_active_task()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void task_refresh_thumbnail(Task *task)
|
||||||
|
{
|
||||||
|
cairo_surface_t *thumbnail = get_window_thumbnail(task->win);
|
||||||
|
if (!thumbnail)
|
||||||
|
return;
|
||||||
|
if (task->thumbnail)
|
||||||
|
cairo_surface_destroy(task->thumbnail);
|
||||||
|
task->thumbnail = thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
void set_task_state(Task *task, TaskState state)
|
void set_task_state(Task *task, TaskState state)
|
||||||
{
|
{
|
||||||
if (!task || state == TASK_UNDEFINED || state >= TASK_STATE_COUNT)
|
if (!task || state == TASK_UNDEFINED || state >= TASK_STATE_COUNT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (state != TASK_ICONIFIED) {
|
||||||
|
task_refresh_thumbnail(task);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == TASK_ACTIVE && task->current_state != state) {
|
if (state == TASK_ACTIVE && task->current_state != state) {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &task->last_activation_time);
|
clock_gettime(CLOCK_MONOTONIC, &task->last_activation_time);
|
||||||
if (taskbar_sort_method == TASKBAR_SORT_LRU || taskbar_sort_method == TASKBAR_SORT_MRU) {
|
if (taskbar_sort_method == TASKBAR_SORT_LRU || taskbar_sort_method == TASKBAR_SORT_MRU) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ typedef struct Task {
|
||||||
double _text_posy;
|
double _text_posy;
|
||||||
int _icon_x;
|
int _icon_x;
|
||||||
int _icon_y;
|
int _icon_y;
|
||||||
|
cairo_surface_t *thumbnail;
|
||||||
} Task;
|
} Task;
|
||||||
|
|
||||||
extern timeout *urgent_timeout;
|
extern timeout *urgent_timeout;
|
||||||
|
|
|
@ -55,7 +55,7 @@ void cleanup_tooltip()
|
||||||
{
|
{
|
||||||
stop_tooltip_timeout();
|
stop_tooltip_timeout();
|
||||||
tooltip_hide(NULL);
|
tooltip_hide(NULL);
|
||||||
tooltip_copy_text(NULL);
|
tooltip_update_contents_for(NULL);
|
||||||
if (g_tooltip.window)
|
if (g_tooltip.window)
|
||||||
XDestroyWindow(server.display, g_tooltip.window);
|
XDestroyWindow(server.display, g_tooltip.window);
|
||||||
g_tooltip.window = 0;
|
g_tooltip.window = 0;
|
||||||
|
@ -118,7 +118,7 @@ void tooltip_trigger_show(Area *area, Panel *p, XEvent *e)
|
||||||
just_shown = TRUE;
|
just_shown = TRUE;
|
||||||
g_tooltip.panel = p;
|
g_tooltip.panel = p;
|
||||||
if (g_tooltip.mapped && g_tooltip.area != area) {
|
if (g_tooltip.mapped && g_tooltip.area != area) {
|
||||||
tooltip_copy_text(area);
|
tooltip_update_contents_for(area);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
stop_tooltip_timeout();
|
stop_tooltip_timeout();
|
||||||
} else if (!g_tooltip.mapped) {
|
} else if (!g_tooltip.mapped) {
|
||||||
|
@ -133,7 +133,7 @@ void tooltip_show(void *arg)
|
||||||
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
|
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
|
||||||
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
|
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
|
||||||
if (!g_tooltip.mapped && area->_get_tooltip_text) {
|
if (!g_tooltip.mapped && area->_get_tooltip_text) {
|
||||||
tooltip_copy_text(area);
|
tooltip_update_contents_for(area);
|
||||||
g_tooltip.mapped = True;
|
g_tooltip.mapped = True;
|
||||||
XMapWindow(server.display, g_tooltip.window);
|
XMapWindow(server.display, g_tooltip.window);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
|
@ -162,6 +162,12 @@ void tooltip_update_geometry()
|
||||||
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
||||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
||||||
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
||||||
|
if (g_tooltip.image) {
|
||||||
|
width = MAX(width,
|
||||||
|
left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx +
|
||||||
|
cairo_image_surface_get_width(g_tooltip.image));
|
||||||
|
height += g_tooltip.paddingy + cairo_image_surface_get_height(g_tooltip.image);
|
||||||
|
}
|
||||||
|
|
||||||
if (panel_horizontal && panel_position & BOTTOM)
|
if (panel_horizontal && panel_position & BOTTOM)
|
||||||
y = panel->posy - height;
|
y = panel->posy - height;
|
||||||
|
@ -278,8 +284,16 @@ void tooltip_update()
|
||||||
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
||||||
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
|
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
|
||||||
pango_cairo_show_layout(c, layout);
|
pango_cairo_show_layout(c, layout);
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
|
|
||||||
|
if (g_tooltip.image) {
|
||||||
|
cairo_translate(c,
|
||||||
|
g_tooltip.paddingx,
|
||||||
|
height - g_tooltip.paddingy - cairo_image_surface_get_height(g_tooltip.image));
|
||||||
|
cairo_set_source_surface(c, g_tooltip.image, 0, 0);
|
||||||
|
cairo_paint(c);
|
||||||
|
}
|
||||||
|
|
||||||
cairo_destroy(c);
|
cairo_destroy(c);
|
||||||
cairo_surface_destroy(cs);
|
cairo_surface_destroy(cs);
|
||||||
}
|
}
|
||||||
|
@ -287,7 +301,7 @@ void tooltip_update()
|
||||||
void tooltip_trigger_hide()
|
void tooltip_trigger_hide()
|
||||||
{
|
{
|
||||||
if (g_tooltip.mapped) {
|
if (g_tooltip.mapped) {
|
||||||
tooltip_copy_text(0);
|
tooltip_update_contents_for(NULL);
|
||||||
start_hide_timeout();
|
start_hide_timeout();
|
||||||
} else {
|
} else {
|
||||||
// tooltip not visible yet, but maybe a timeout is still pending
|
// tooltip not visible yet, but maybe a timeout is still pending
|
||||||
|
@ -319,12 +333,23 @@ void stop_tooltip_timeout()
|
||||||
stop_timeout(g_tooltip.timeout);
|
stop_timeout(g_tooltip.timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tooltip_copy_text(Area *area)
|
void tooltip_update_contents_for(Area *area)
|
||||||
{
|
{
|
||||||
free(g_tooltip.tooltip_text);
|
free(g_tooltip.tooltip_text);
|
||||||
if (area && area->_get_tooltip_text)
|
if (area && area->_get_tooltip_text)
|
||||||
g_tooltip.tooltip_text = area->_get_tooltip_text(area);
|
g_tooltip.tooltip_text = area->_get_tooltip_text(area);
|
||||||
else
|
else
|
||||||
g_tooltip.tooltip_text = NULL;
|
g_tooltip.tooltip_text = NULL;
|
||||||
|
if (area && area->_get_tooltip_image) {
|
||||||
|
if (g_tooltip.image)
|
||||||
|
cairo_surface_destroy(g_tooltip.image);
|
||||||
|
g_tooltip.image = area->_get_tooltip_image(area);
|
||||||
|
if (g_tooltip.image)
|
||||||
|
cairo_surface_reference(g_tooltip.image);
|
||||||
|
} else {
|
||||||
|
if (g_tooltip.image)
|
||||||
|
cairo_surface_destroy(g_tooltip.image);
|
||||||
|
g_tooltip.image = NULL;
|
||||||
|
}
|
||||||
g_tooltip.area = area;
|
g_tooltip.area = area;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ typedef struct {
|
||||||
Color font_color;
|
Color font_color;
|
||||||
Background *bg;
|
Background *bg;
|
||||||
timeout *timeout;
|
timeout *timeout;
|
||||||
|
cairo_surface_t *image;
|
||||||
} Tooltip;
|
} Tooltip;
|
||||||
|
|
||||||
extern Tooltip g_tooltip;
|
extern Tooltip g_tooltip;
|
||||||
|
@ -53,7 +54,7 @@ void tooltip_show(void * /*arg*/);
|
||||||
void tooltip_update();
|
void tooltip_update();
|
||||||
void tooltip_trigger_hide();
|
void tooltip_trigger_hide();
|
||||||
void tooltip_hide(void * /*arg*/);
|
void tooltip_hide(void * /*arg*/);
|
||||||
void tooltip_copy_text(Area *area);
|
void tooltip_update_contents_for(Area *area);
|
||||||
void tooltip_default_font_changed();
|
void tooltip_default_font_changed();
|
||||||
|
|
||||||
#endif // TOOLTIP_H
|
#endif // TOOLTIP_H
|
||||||
|
|
|
@ -233,6 +233,7 @@ typedef struct Area {
|
||||||
// Returns a copy of the tooltip to be displayed for this widget.
|
// Returns a copy of the tooltip to be displayed for this widget.
|
||||||
// The caller takes ownership of the pointer.
|
// The caller takes ownership of the pointer.
|
||||||
char *(*_get_tooltip_text)(void *obj);
|
char *(*_get_tooltip_text)(void *obj);
|
||||||
|
cairo_surface_t *(*_get_tooltip_image)(void *obj);
|
||||||
|
|
||||||
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
|
// 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.
|
// Leave this to NULL to use a default implementation.
|
||||||
|
|
|
@ -157,7 +157,8 @@ int get_window_desktop(Window win)
|
||||||
|
|
||||||
if (best_match < 0)
|
if (best_match < 0)
|
||||||
best_match = 0;
|
best_match = 0;
|
||||||
// fprintf(stderr, "tint2: window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title : "??",
|
// fprintf(stderr, "tint2: window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title :
|
||||||
|
// "??",
|
||||||
// best_match+1, x, y);
|
// best_match+1, x, y);
|
||||||
return best_match;
|
return best_match;
|
||||||
}
|
}
|
||||||
|
@ -190,15 +191,18 @@ int get_window_monitor(Window win)
|
||||||
return best_match;
|
return best_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
|
gboolean get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
|
||||||
{
|
{
|
||||||
int dummy_int;
|
int dummy_int;
|
||||||
unsigned ww, wh, bw, bh;
|
unsigned ww, wh, bw, bh;
|
||||||
Window src;
|
Window src;
|
||||||
XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src);
|
if (!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);
|
return FALSE;
|
||||||
|
if (!XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh))
|
||||||
|
return FALSE;
|
||||||
*w = ww + bw;
|
*w = ww + bw;
|
||||||
*h = wh + bh;
|
*h = wh + bh;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean window_is_iconified(Window win)
|
gboolean window_is_iconified(Window win)
|
||||||
|
@ -352,3 +356,39 @@ char *get_window_name(Window win)
|
||||||
XFree(text_property.value);
|
XFree(text_property.value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cairo_surface_t *get_window_thumbnail(Window win)
|
||||||
|
{
|
||||||
|
int x, y, w, h;
|
||||||
|
if (!get_window_coordinates(win, &x, &y, &w, &h))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int tw, th;
|
||||||
|
th = 128;
|
||||||
|
tw = w * th / h;
|
||||||
|
|
||||||
|
cairo_surface_t *x11_surface =
|
||||||
|
cairo_xlib_surface_create(server.display, win, DefaultVisual(server.display, server.screen), w, h);
|
||||||
|
cairo_surface_t *image_surface = cairo_surface_create_similar_image(x11_surface, CAIRO_FORMAT_ARGB32, tw, th);
|
||||||
|
|
||||||
|
cairo_t *cr = cairo_create(image_surface);
|
||||||
|
cairo_scale(cr, tw/(double)w, th/(double)h);
|
||||||
|
cairo_set_source_surface(cr, x11_surface, 0, 0);
|
||||||
|
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BEST);
|
||||||
|
cairo_paint(cr);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
cairo_surface_destroy(x11_surface);
|
||||||
|
|
||||||
|
uint32_t *pixels = (uint32_t *)cairo_image_surface_get_data(image_surface);
|
||||||
|
gboolean empty = TRUE;
|
||||||
|
for (int i = 0; empty && i < tw * th; i += 4) {
|
||||||
|
if (pixels[i] & 0xffFFff)
|
||||||
|
empty = FALSE;
|
||||||
|
}
|
||||||
|
if (empty) {
|
||||||
|
cairo_surface_destroy(image_surface);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image_surface;
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ int get_window_monitor(Window win);
|
||||||
|
|
||||||
void activate_window(Window win);
|
void activate_window(Window win);
|
||||||
void close_window(Window win);
|
void close_window(Window win);
|
||||||
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h);
|
gboolean get_window_coordinates(Window win, int *x, int *y, int *w, int *h);
|
||||||
void toggle_window_maximized(Window win);
|
void toggle_window_maximized(Window win);
|
||||||
void toggle_window_shade(Window win);
|
void toggle_window_shade(Window win);
|
||||||
void change_window_desktop(Window win, int desktop);
|
void change_window_desktop(Window win, int desktop);
|
||||||
|
@ -34,5 +34,6 @@ int get_icon_count(gulong *data, int num);
|
||||||
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
|
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
|
||||||
|
|
||||||
char *get_window_name(Window win);
|
char *get_window_name(Window win);
|
||||||
|
cairo_surface_t *get_window_thumbnail(Window win);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue