Support for NETWM viewports (compiz)

This commit is contained in:
o9000
2015-11-21 04:35:12 +01:00
parent 4a6937826c
commit eb044da8bc
11 changed files with 537 additions and 349 deletions

View File

@@ -258,7 +258,7 @@ void init_panel()
} }
task_refresh_tasklist(); task_refresh_tasklist();
active_task(); reset_active_task();
} }
void init_panel_size_and_position(Panel *panel) void init_panel_size_and_position(Panel *panel)
@@ -576,7 +576,7 @@ void set_panel_properties(Panel *p)
(unsigned char *)&val, (unsigned char *)&val,
1); 1);
val = ALLDESKTOP; val = ALL_DESKTOPS;
XChangeProperty(server.dsp, XChangeProperty(server.dsp,
p->main_win, p->main_win,
server.atom._NET_WM_DESKTOP, server.atom._NET_WM_DESKTOP,

View File

@@ -29,7 +29,7 @@
#include "config.h" #include "config.h"
#include "window.h" #include "window.h"
Server_global server; Server server;
void server_catch_error(Display *d, XErrorEvent *ev) void server_catch_error(Display *d, XErrorEvent *ev)
{ {
@@ -44,6 +44,7 @@ void server_init_atoms()
server.atom._NET_DESKTOP_NAMES = XInternAtom(server.dsp, "_NET_DESKTOP_NAMES", False); server.atom._NET_DESKTOP_NAMES = XInternAtom(server.dsp, "_NET_DESKTOP_NAMES", False);
server.atom._NET_DESKTOP_GEOMETRY = XInternAtom(server.dsp, "_NET_DESKTOP_GEOMETRY", False); server.atom._NET_DESKTOP_GEOMETRY = XInternAtom(server.dsp, "_NET_DESKTOP_GEOMETRY", False);
server.atom._NET_DESKTOP_VIEWPORT = XInternAtom(server.dsp, "_NET_DESKTOP_VIEWPORT", False); server.atom._NET_DESKTOP_VIEWPORT = XInternAtom(server.dsp, "_NET_DESKTOP_VIEWPORT", False);
server.atom._NET_WORKAREA = XInternAtom(server.dsp, "_NET_WORKAREA", False);
server.atom._NET_ACTIVE_WINDOW = XInternAtom(server.dsp, "_NET_ACTIVE_WINDOW", False); server.atom._NET_ACTIVE_WINDOW = XInternAtom(server.dsp, "_NET_ACTIVE_WINDOW", False);
server.atom._NET_WM_WINDOW_TYPE = XInternAtom(server.dsp, "_NET_WM_WINDOW_TYPE", False); server.atom._NET_WM_WINDOW_TYPE = XInternAtom(server.dsp, "_NET_WM_WINDOW_TYPE", False);
server.atom._NET_WM_STATE_SKIP_PAGER = XInternAtom(server.dsp, "_NET_WM_STATE_SKIP_PAGER", False); server.atom._NET_WM_STATE_SKIP_PAGER = XInternAtom(server.dsp, "_NET_WM_STATE_SKIP_PAGER", False);
@@ -388,9 +389,127 @@ void print_monitors()
} }
} }
int server_get_number_of_desktops() void server_get_number_of_desktops()
{ {
return get_property32(server.root_win, server.atom._NET_NUMBER_OF_DESKTOPS, XA_CARDINAL); if (server.viewports) {
free(server.viewports);
server.viewports = NULL;
}
server.num_desktops = get_property32(server.root_win, server.atom._NET_NUMBER_OF_DESKTOPS, XA_CARDINAL);
if (server.num_desktops > 1)
return;
int num_results;
long *work_area_size = server_get_property(server.root_win, server.atom._NET_WORKAREA, XA_CARDINAL, &num_results);
if (!work_area_size)
return;
int work_area_width = work_area_size[0] + work_area_size[2];
int work_area_height = work_area_size[1] + work_area_size[3];
XFree(work_area_size);
long *x_screen_size = server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
if (!x_screen_size)
return;
int x_screen_width = x_screen_size[0];
int x_screen_height = x_screen_size[1];
XFree(x_screen_size);
int num_viewports = MAX(x_screen_width / work_area_width, 1) * MAX(x_screen_height / work_area_height, 1);
if (num_viewports <= 1)
return;
server.viewports = calloc(num_viewports, sizeof(Viewport));
int k = 0;
for (int i = 0; i < MAX(x_screen_height / work_area_height, 1); i++) {
for (int j = 0; j < MAX(x_screen_width / work_area_width, 1); j++) {
server.viewports[k].x = j * work_area_width;
server.viewports[k].y = i * work_area_height;
server.viewports[k].width = work_area_width;
server.viewports[k].height = work_area_height;
k++;
}
}
server.num_desktops = num_viewports;
}
GSList *get_desktop_names()
{
if (server.viewports) {
GSList *list = NULL;
for (int j = 0; j < server.num_desktops; j++) {
list = g_slist_append(list, g_strdup_printf("%d", j + 1));
}
return list;
}
int count;
GSList *list = NULL;
gchar *data_ptr = server_get_property(server.root_win, server.atom._NET_DESKTOP_NAMES, server.atom.UTF8_STRING, &count);
if (data_ptr) {
list = g_slist_append(list, g_strdup(data_ptr));
for (int j = 0; j < count - 1; j++) {
if (*(data_ptr + j) == '\0') {
gchar *ptr = (gchar *)data_ptr + j + 1;
list = g_slist_append(list, g_strdup(ptr));
}
}
XFree(data_ptr);
}
return list;
}
int get_current_desktop()
{
if (!server.viewports)
return get_property32(server.root_win, server.atom._NET_CURRENT_DESKTOP, XA_CARDINAL);
int num_results;
long *work_area_size = server_get_property(server.root_win, server.atom._NET_WORKAREA, XA_CARDINAL, &num_results);
if (!work_area_size)
return 0;
int work_area_width = work_area_size[0] + work_area_size[2];
int work_area_height = work_area_size[1] + work_area_size[3];
XFree(work_area_size);
if (work_area_width <= 0 || work_area_height <= 0)
return 0;
long *viewport = server_get_property(server.root_win, server.atom._NET_DESKTOP_VIEWPORT, XA_CARDINAL, &num_results);
if (!viewport)
return 0;
int viewport_x = viewport[0];
int viewport_y = viewport[1];
XFree(viewport);
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];
XFree(x_screen_size);
int ncols = x_screen_width / work_area_width;
// fprintf(stderr, "\n");
// fprintf(stderr, "Work area size: %d x %d\n", work_area_width, work_area_height);
// fprintf(stderr, "Viewport pos: %d x %d\n", viewport_x, viewport_y);
// fprintf(stderr, "Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x / work_area_width);
return (viewport_y / work_area_height) * ncols + viewport_x / work_area_width;
}
void change_desktop(int desktop)
{
if (!server.viewports) {
send_event32(server.root_win, server.atom._NET_CURRENT_DESKTOP, desktop, 0, 0);
} else {
send_event32(server.root_win,
server.atom._NET_DESKTOP_VIEWPORT,
server.viewports[desktop].x,
server.viewports[desktop].y,
0);
}
} }
void get_desktops() void get_desktops()
@@ -398,7 +517,7 @@ void get_desktops()
// detect number of desktops // detect number of desktops
// wait 15s to leave some time for window manager startup // wait 15s to leave some time for window manager startup
for (int i = 0; i < 15; i++) { for (int i = 0; i < 15; i++) {
server.num_desktops = server_get_number_of_desktops(); server_get_number_of_desktops();
if (server.num_desktops > 0) if (server.num_desktops > 0)
break; break;
sleep(1); sleep(1);

View File

@@ -26,6 +26,7 @@ typedef struct Global_atom {
Atom _NET_DESKTOP_NAMES; Atom _NET_DESKTOP_NAMES;
Atom _NET_DESKTOP_GEOMETRY; Atom _NET_DESKTOP_GEOMETRY;
Atom _NET_DESKTOP_VIEWPORT; Atom _NET_DESKTOP_VIEWPORT;
Atom _NET_WORKAREA;
Atom _NET_ACTIVE_WINDOW; Atom _NET_ACTIVE_WINDOW;
Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE;
Atom _NET_WM_STATE_SKIP_PAGER; Atom _NET_WM_STATE_SKIP_PAGER;
@@ -98,7 +99,14 @@ typedef struct Monitor {
gchar **names; gchar **names;
} Monitor; } Monitor;
typedef struct { typedef struct Viewport {
int x;
int y;
int width;
int height;
} Viewport;
typedef struct Server {
Display *dsp; Display *dsp;
Window root_win; Window root_win;
Window composite_manager; Window composite_manager;
@@ -111,6 +119,9 @@ typedef struct {
int num_desktops; int num_desktops;
// number of monitor (without monitor included into another one) // number of monitor (without monitor included into another one)
int num_monitors; int num_monitors;
// Non-null only if WM uses viewports (compiz) and number of viewports > 1.
// In that case there are num_desktops viewports.
Viewport *viewports;
Monitor *monitor; Monitor *monitor;
int got_root_win; int got_root_win;
Visual *visual; Visual *visual;
@@ -125,9 +136,9 @@ typedef struct {
SnDisplay *sn_dsp; SnDisplay *sn_dsp;
GTree *pids; GTree *pids;
#endif // HAVE_SN #endif // HAVE_SN
} Server_global; } Server;
extern Server_global server; extern Server server;
// freed memory // freed memory
void cleanup_server(); void cleanup_server();
@@ -147,6 +158,10 @@ void get_root_pixmap();
void get_monitors(); void get_monitors();
void print_monitors(); void print_monitors();
void get_desktops(); void get_desktops();
int server_get_number_of_desktops(); void server_get_number_of_desktops();
GSList *get_desktop_names();
int get_current_desktop();
void change_desktop(int desktop);
#endif #endif

View File

@@ -18,22 +18,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**************************************************************************/ **************************************************************************/
#include <X11/Xlib.h> #include <glib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <glib.h>
#include <unistd.h> #include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "window.h" #include "panel.h"
#include "server.h"
#include "task.h" #include "task.h"
#include "taskbar.h" #include "taskbar.h"
#include "server.h"
#include "panel.h"
#include "tooltip.h"
#include "timer.h" #include "timer.h"
#include "tooltip.h"
#include "window.h"
timeout *urgent_timeout; timeout *urgent_timeout;
GSList *urgent_list; GSList *urgent_list;
@@ -47,102 +47,99 @@ char *task_get_tooltip(void *obj)
Task *add_task(Window win) Task *add_task(Window win)
{ {
if (!win) if (!win)
return 0; return NULL;
if (window_is_hidden(win)) if (window_is_hidden(win))
return 0; return NULL;
XSelectInput(server.dsp, win, PropertyChangeMask | StructureNotifyMask); XSelectInput(server.dsp, win, PropertyChangeMask | StructureNotifyMask);
XFlush(server.dsp); XFlush(server.dsp);
int monitor; int monitor = 0;
if (num_panels > 1) { if (num_panels > 1) {
monitor = get_window_monitor(win); monitor = get_window_monitor(win);
if (monitor >= num_panels) if (monitor >= num_panels)
monitor = 0; monitor = 0;
} else }
monitor = 0;
Task new_task; // TODO why do we add the task only to the panel for the current monitor, without checking hide_task_diff_monitor?
memset(&new_task, 0, sizeof(new_task));
new_task.area.has_mouse_over_effect = 1; Task task_template;
new_task.area.has_mouse_press_effect = 1; memset(&task_template, 0, sizeof(task_template));
new_task.win = win; task_template.area.has_mouse_over_effect = TRUE;
new_task.desktop = get_window_desktop(win); task_template.area.has_mouse_press_effect = TRUE;
new_task.area.panel = &panels[monitor]; task_template.win = win;
new_task.current_state = window_is_iconified(win) ? TASK_ICONIFIED : TASK_NORMAL; task_template.desktop = get_window_desktop(win);
get_window_coordinates(win, &new_task.win_x, &new_task.win_y, &new_task.win_w, &new_task.win_h); task_template.area.panel = &panels[monitor];
task_template.current_state = window_is_iconified(win) ? TASK_ICONIFIED : TASK_NORMAL;
get_window_coordinates(win, &task_template.win_x, &task_template.win_y, &task_template.win_w, &task_template.win_h);
// allocate only one title and one icon // allocate only one title and one icon
// even with task_on_all_desktop and with task_on_all_panel // even with task_on_all_desktop and with task_on_all_panel
new_task.title = 0; task_template.title = NULL;
int k; for (int k = 0; k < TASK_STATE_COUNT; ++k) {
for (k = 0; k < TASK_STATE_COUNT; ++k) { task_template.icon[k] = NULL;
new_task.icon[k] = 0; task_template.state_pix[k] = 0;
new_task.state_pix[k] = 0;
} }
get_title(&new_task); get_title(&task_template);
get_icon(&new_task); get_icon(&task_template);
// printf("new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor); // printf("new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor);
GPtrArray *task_group = g_ptr_array_new(); GPtrArray *task_group = g_ptr_array_new();
Taskbar *taskbar; for (int j = 0; j < panels[monitor].num_desktops; j++) {
Task *new_task2 = 0; if (task_template.desktop != ALL_DESKTOPS && task_template.desktop != j)
int j;
for (j = 0; j < panels[monitor].num_desktops; j++) {
if (new_task.desktop != ALLDESKTOP && new_task.desktop != j)
continue; continue;
taskbar = &panels[monitor].taskbar[j]; Taskbar *taskbar = &panels[monitor].taskbar[j];
new_task2 = calloc(1, sizeof(Task)); Task *task_instance = calloc(1, sizeof(Task));
memcpy(&new_task2->area, &panels[monitor].g_task.area, sizeof(Area)); memcpy(&task_instance->area, &panels[monitor].g_task.area, sizeof(Area));
new_task2->area.parent = taskbar; task_instance->area.has_mouse_over_effect = TRUE;
new_task2->area.has_mouse_over_effect = 1; task_instance->area.has_mouse_press_effect = TRUE;
new_task2->area.has_mouse_press_effect = 1; task_instance->win = task_template.win;
new_task2->win = new_task.win; task_instance->desktop = task_template.desktop;
new_task2->desktop = new_task.desktop; task_instance->win_x = task_template.win_x;
new_task2->win_x = new_task.win_x; task_instance->win_y = task_template.win_y;
new_task2->win_y = new_task.win_y; task_instance->win_w = task_template.win_w;
new_task2->win_w = new_task.win_w; task_instance->win_h = task_template.win_h;
new_task2->win_h = new_task.win_h; task_instance->current_state = -1; // to update the current state later in set_task_state...
new_task2->current_state = -1; // to update the current state later in set_task_state... if (task_instance->desktop == ALL_DESKTOPS && server.desktop != j) {
if (new_task2->desktop == ALLDESKTOP && server.desktop != j) { // hide ALL_DESKTOPS task on non-current desktop
// hide ALLDESKTOP task on non-current desktop task_instance->area.on_screen = FALSE;
new_task2->area.on_screen = FALSE;
} }
new_task2->title = new_task.title; task_instance->title = task_template.title;
if (panels[monitor].g_task.tooltip_enabled) if (panels[monitor].g_task.tooltip_enabled)
new_task2->area._get_tooltip_text = task_get_tooltip; task_instance->area._get_tooltip_text = task_get_tooltip;
for (k = 0; k < TASK_STATE_COUNT; ++k) { for (int k = 0; k < TASK_STATE_COUNT; ++k) {
new_task2->icon[k] = new_task.icon[k]; task_instance->icon[k] = task_template.icon[k];
new_task2->icon_hover[k] = new_task.icon_hover[k]; task_instance->icon_hover[k] = task_template.icon_hover[k];
new_task2->icon_press[k] = new_task.icon_press[k]; task_instance->icon_press[k] = task_template.icon_press[k];
new_task2->state_pix[k] = 0; task_instance->state_pix[k] = 0;
} }
new_task2->icon_width = new_task.icon_width; task_instance->icon_width = task_template.icon_width;
new_task2->icon_height = new_task.icon_height; task_instance->icon_height = task_template.icon_height;
taskbar->area.children = g_list_append(taskbar->area.children, new_task2);
taskbar->area.resize_needed = 1; add_area(&task_instance->area, &taskbar->area);
g_ptr_array_add(task_group, new_task2); g_ptr_array_add(task_group, task_instance);
// printf("add_task panel %d, desktop %d, task %s\n", i, j, new_task2->title); // printf("add_task panel %d, desktop %d, task %s\n", i, j, task_instance->title);
} }
Window *key = calloc(1, sizeof(Window)); Window *key = calloc(1, sizeof(Window));
*key = new_task.win; *key = task_template.win;
g_hash_table_insert(win_to_task_table, key, task_group); g_hash_table_insert(win_to_task, key, task_group);
set_task_state(new_task2, new_task.current_state);
set_task_state((Task*)g_ptr_array_index(task_group, 0), task_template.current_state);
sort_taskbar_for_win(win); sort_taskbar_for_win(win);
if (taskbar_mode == MULTI_DESKTOP) { if (taskbar_mode == MULTI_DESKTOP) {
Panel *panel = new_task2->area.panel; Panel *panel = (Panel*)task_template.area.panel;
panel->area.resize_needed = 1; panel->area.resize_needed = TRUE;
} }
if (window_is_urgent(win)) { if (window_is_urgent(win)) {
add_urgent(new_task2); add_urgent((Task*)g_ptr_array_index(task_group, 0));
} }
return new_task2; return (Task*)g_ptr_array_index(task_group, 0);
} }
void remove_task(Task *task) void remove_task(Task *task)
@@ -162,8 +159,7 @@ void remove_task(Task *task)
// printf("remove_task %s %d\n", task->title, task->desktop); // printf("remove_task %s %d\n", task->title, task->desktop);
if (task->title) if (task->title)
free(task->title); free(task->title);
int k; for (int k = 0; k < TASK_STATE_COUNT; ++k) {
for (k = 0; k < TASK_STATE_COUNT; ++k) {
if (task->icon[k]) { if (task->icon[k]) {
imlib_context_set_image(task->icon[k]); imlib_context_set_image(task->icon[k]);
imlib_free_image(); imlib_free_image();
@@ -183,13 +179,11 @@ void remove_task(Task *task)
XFreePixmap(server.dsp, task->state_pix[k]); XFreePixmap(server.dsp, task->state_pix[k]);
} }
int i; GPtrArray *task_group = g_hash_table_lookup(win_to_task, &win);
Task *task2; for (int i = 0; i < task_group->len; ++i) {
GPtrArray *task_group = g_hash_table_lookup(win_to_task_table, &win); Task *task2 = g_ptr_array_index(task_group, i);
for (i = 0; i < task_group->len; ++i) { if (task2 == active_task)
task2 = g_ptr_array_index(task_group, i); active_task = 0;
if (task2 == task_active)
task_active = 0;
if (task2 == task_drag) if (task2 == task_drag)
task_drag = 0; task_drag = 0;
if (g_slist_find(urgent_list, task2)) if (g_slist_find(urgent_list, task2))
@@ -197,18 +191,17 @@ void remove_task(Task *task)
remove_area((Area *)task2); remove_area((Area *)task2);
free(task2); free(task2);
} }
g_hash_table_remove(win_to_task_table, &win); g_hash_table_remove(win_to_task, &win);
} }
gboolean get_title(Task *task) gboolean get_title(Task *task)
{ {
Panel *panel = task->area.panel; Panel *panel = task->area.panel;
char *title, *name;
if (!panel->g_task.text && !panel->g_task.tooltip_enabled && taskbar_sort_method != TASKBAR_SORT_TITLE) if (!panel->g_task.text && !panel->g_task.tooltip_enabled && taskbar_sort_method != TASKBAR_SORT_TITLE)
return 0; return FALSE;
name = server_get_property(task->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0); char *name = server_get_property(task->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
if (!name || !strlen(name)) { if (!name || !strlen(name)) {
name = server_get_property(task->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0); name = server_get_property(task->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0);
if (!name || !strlen(name)) { if (!name || !strlen(name)) {
@@ -216,6 +209,7 @@ gboolean get_title(Task *task)
} }
} }
char *title;
if (name && strlen(name)) { if (name && strlen(name)) {
title = strdup(name); title = strdup(name);
} else { } else {
@@ -228,22 +222,22 @@ gboolean get_title(Task *task)
// check unecessary title change // check unecessary title change
if (strcmp(task->title, title) == 0) { if (strcmp(task->title, title) == 0) {
free(title); free(title);
return 0; return FALSE;
} else } else {
free(task->title); free(task->title);
}
} }
task->title = title; task->title = title;
GPtrArray *task_group = task_get_tasks(task->win); GPtrArray *task_group = task_get_tasks(task->win);
if (task_group) { if (task_group) {
int i; for (int i = 0; i < task_group->len; ++i) {
for (i = 0; i < task_group->len; ++i) {
Task *task2 = g_ptr_array_index(task_group, i); Task *task2 = g_ptr_array_index(task_group, i);
task2->title = task->title; task2->title = task->title;
set_task_redraw(task2); set_task_redraw(task2);
} }
} }
return 1; return TRUE;
} }
void get_icon(Task *task) void get_icon(Task *task)
@@ -251,7 +245,7 @@ void get_icon(Task *task)
Panel *panel = task->area.panel; Panel *panel = task->area.panel;
if (!panel->g_task.icon) if (!panel->g_task.icon)
return; return;
int i;
Imlib_Image img = NULL; Imlib_Image img = NULL;
XWMHints *hints = 0; XWMHints *hints = 0;
gulong *data = 0; gulong *data = 0;
@@ -264,6 +258,7 @@ void get_icon(Task *task)
} }
} }
int i;
data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &i); data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &i);
if (data) { if (data) {
// get ARGB icon // get ARGB icon
@@ -306,9 +301,8 @@ void get_icon(Task *task)
// transform icons // transform icons
imlib_context_set_image(img); imlib_context_set_image(img);
imlib_image_set_has_alpha(1); imlib_image_set_has_alpha(1);
int w, h; int w = imlib_image_get_width();
w = imlib_image_get_width(); int h = imlib_image_get_height();
h = imlib_image_get_height();
Imlib_Image orig_image = Imlib_Image orig_image =
imlib_create_cropped_scaled_image(0, 0, w, h, panel->g_task.icon_size1, panel->g_task.icon_size1); imlib_create_cropped_scaled_image(0, 0, w, h, panel->g_task.icon_size1, panel->g_task.icon_size1);
imlib_free_image(); imlib_free_image();
@@ -380,8 +374,9 @@ void draw_task_icon(Task *task, int text_width)
pos_x = (task->area.width - text_width - panel->g_task.icon_size1) / 2; pos_x = (task->area.width - text_width - panel->g_task.icon_size1) / 2;
else else
pos_x = (task->area.width - panel->g_task.icon_size1) / 2; pos_x = (task->area.width - panel->g_task.icon_size1) / 2;
} else } else {
pos_x = panel->g_task.area.paddingxlr + task->area.bg->border.width; pos_x = panel->g_task.area.paddingxlr + task->area.bg->border.width;
}
// Render // Render
@@ -404,53 +399,46 @@ void draw_task_icon(Task *task, int text_width)
void draw_task(void *obj, cairo_t *c) void draw_task(void *obj, cairo_t *c)
{ {
Task *task = obj; Task *task = (Task *)obj;
Panel *panel = (Panel *)task->area.panel;
if (!panel_config.mouse_effects) if (!panel_config.mouse_effects)
task->state_pix[task->current_state] = task->area.pix; task->state_pix[task->current_state] = task->area.pix;
PangoLayout *layout;
Color *config_text;
int width = 0, height;
Panel *panel = (Panel *)task->area.panel;
// printf("draw_task %d %d\n", task->area.posx, task->area.posy);
int text_width = 0;
if (panel->g_task.text) { if (panel->g_task.text) {
/* Layout */ PangoLayout *layout = pango_cairo_create_layout(c);
layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, panel->g_task.font_desc); pango_layout_set_font_description(layout, panel->g_task.font_desc);
pango_layout_set_text(layout, task->title, -1); pango_layout_set_text(layout, task->title, -1);
/* Drawing width and Cut text */
// pango use U+22EF or U+2026
pango_layout_set_width(layout, ((Taskbar *)task->area.parent)->text_width * PANGO_SCALE); pango_layout_set_width(layout, ((Taskbar *)task->area.parent)->text_width * PANGO_SCALE);
pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE); pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
/* Center text */
if (panel->g_task.centered) if (panel->g_task.centered)
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
else else
pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
pango_layout_get_pixel_size(layout, &width, &height); int text_height;
pango_layout_get_pixel_size(layout, &text_width, &text_height);
config_text = &panel->g_task.font[task->current_state]; double text_posy = (panel->g_task.area.height - text_height) / 2.0;
double text_posy = (panel->g_task.area.height - height) / 2.0;
Color *config_text = &panel->g_task.font[task->current_state];
draw_text(layout, c, panel->g_task.text_posx, text_posy, config_text, panel->font_shadow); draw_text(layout, c, panel->g_task.text_posx, text_posy, config_text, panel->font_shadow);
g_object_unref(layout); g_object_unref(layout);
} }
if (panel->g_task.icon) { if (panel->g_task.icon) {
draw_task_icon(task, width); draw_task_icon(task, text_width);
} }
} }
void on_change_task(void *obj) void on_change_task(void *obj)
{ {
Task *task = obj; Task *task = (Task *)obj;
Panel *panel = (Panel *)task->area.panel; Panel *panel = (Panel *)task->area.panel;
long value[] = {panel->posx + task->area.posx, panel->posy + task->area.posy, task->area.width, task->area.height}; long value[] = {panel->posx + task->area.posx, panel->posy + task->area.posy, task->area.width, task->area.height};
@@ -467,21 +455,18 @@ void on_change_task(void *obj)
set_task_redraw(task); set_task_redraw(task);
} }
// Given a pointer to the active task (active_task) and a pointer Task *find_active_task(Task *current_task)
// to the task that is currently under the mouse (current_task),
// returns a pointer to the active task.
Task *find_active_task(Task *current_task, Task *active_task)
{ {
if (active_task == NULL) if (active_task == NULL)
return current_task; return current_task;
Taskbar *taskbar = current_task->area.parent; Taskbar *taskbar = (Taskbar *)current_task->area.parent;
GList *l0 = taskbar->area.children; GList *l0 = taskbar->area.children;
if (taskbarname_enabled) if (taskbarname_enabled)
l0 = l0->next; l0 = l0->next;
for (; l0; l0 = l0->next) { for (; l0; l0 = l0->next) {
Task *task = l0->data; Task *task = (Task *)l0->data;
if (task->win == active_task->win) if (task->win == active_task->win)
return task; return task;
} }
@@ -492,7 +477,7 @@ Task *find_active_task(Task *current_task, Task *active_task)
Task *next_task(Task *task) Task *next_task(Task *task)
{ {
if (!task) if (!task)
return 0; return NULL;
Taskbar *taskbar = task->area.parent; Taskbar *taskbar = task->area.parent;
@@ -508,7 +493,7 @@ Task *next_task(Task *task)
} }
} }
return 0; return NULL;
} }
Task *prev_task(Task *task) Task *prev_task(Task *task)
@@ -535,14 +520,14 @@ Task *prev_task(Task *task)
task2 = task1; task2 = task1;
} }
return 0; return NULL;
} }
void active_task() void reset_active_task()
{ {
if (task_active) { if (active_task) {
set_task_state(task_active, window_is_iconified(task_active->win) ? TASK_ICONIFIED : TASK_NORMAL); set_task_state(active_task, window_is_iconified(active_task->win) ? TASK_ICONIFIED : TASK_NORMAL);
task_active = 0; active_task = NULL;
} }
Window w1 = get_active_window(); Window w1 = get_active_window();
@@ -554,7 +539,7 @@ void active_task()
while (XGetTransientForHint(server.dsp, w1, &w2)) while (XGetTransientForHint(server.dsp, w1, &w2))
w1 = w2; w1 = w2;
} }
set_task_state((task_active = task_get_task(w1)), TASK_ACTIVE); set_task_state((active_task = task_get_task(w1)), TASK_ACTIVE);
} }
} }
@@ -566,8 +551,7 @@ void set_task_state(Task *task, TaskState state)
if (task->current_state != state || hide_task_diff_monitor) { if (task->current_state != state || hide_task_diff_monitor) {
GPtrArray *task_group = task_get_tasks(task->win); GPtrArray *task_group = task_get_tasks(task->win);
if (task_group) { if (task_group) {
int i; for (int i = 0; i < task_group->len; ++i) {
for (i = 0; i < task_group->len; ++i) {
Task *task1 = g_ptr_array_index(task_group, i); Task *task1 = g_ptr_array_index(task_group, i);
task1->current_state = state; task1->current_state = state;
task1->area.bg = panels[0].g_task.background[state]; task1->area.bg = panels[0].g_task.background[state];
@@ -580,29 +564,29 @@ void set_task_state(Task *task, TaskState state)
} }
if (state == TASK_ACTIVE && g_slist_find(urgent_list, task1)) if (state == TASK_ACTIVE && g_slist_find(urgent_list, task1))
del_urgent(task1); del_urgent(task1);
int hide = 0; gboolean hide = FALSE;
Taskbar *taskbar = (Taskbar *)task1->area.parent; Taskbar *taskbar = (Taskbar *)task1->area.parent;
if (task->desktop == ALLDESKTOP && server.desktop != taskbar->desktop) { if (task->desktop == ALL_DESKTOPS && server.desktop != taskbar->desktop) {
// Hide ALLDESKTOP task on non-current desktop // Hide ALL_DESKTOPS task on non-current desktop
hide = 1; hide = TRUE;
} }
if (hide_inactive_tasks) { if (hide_inactive_tasks) {
// Show only the active task // Show only the active task
if (state != TASK_ACTIVE) { if (state != TASK_ACTIVE) {
hide = 1; hide = TRUE;
} }
} }
if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor && if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor &&
(hide_task_diff_monitor || num_panels > 1)) { (hide_task_diff_monitor || num_panels > 1)) {
hide = 1; hide = TRUE;
} }
if (1 - hide != task1->area.on_screen) { if ((!hide) != task1->area.on_screen) {
task1->area.on_screen = TRUE - hide; task1->area.on_screen = !hide;
set_task_redraw(task1); set_task_redraw(task1);
Panel *p = (Panel *)task->area.panel; Panel *p = (Panel *)task->area.panel;
task->area.resize_needed = 1; task->area.resize_needed = TRUE;
p->taskbar->area.resize_needed = 1; p->taskbar->area.resize_needed = TRUE;
p->area.resize_needed = 1; p->area.resize_needed = TRUE;
} }
} }
panel_refresh = TRUE; panel_refresh = TRUE;
@@ -612,8 +596,7 @@ void set_task_state(Task *task, TaskState state)
void set_task_redraw(Task *task) void set_task_redraw(Task *task)
{ {
int k; for (int k = 0; k < TASK_STATE_COUNT; ++k) {
for (k = 0; k < TASK_STATE_COUNT; ++k) {
if (task->state_pix[k]) if (task->state_pix[k])
XFreePixmap(server.dsp, task->state_pix[k]); XFreePixmap(server.dsp, task->state_pix[k]);
task->state_pix[k] = 0; task->state_pix[k] = 0;
@@ -644,7 +627,7 @@ void add_urgent(Task *task)
return; return;
// some programs set urgency hint although they are active // some programs set urgency hint although they are active
if (task_active && task_active->win == task->win) if (active_task && active_task->win == task->win)
return; return;
task = task_get_task(task->win); // always add the first task for a task group (omnipresent windows) task = task_get_task(task->win); // always add the first task for a task group (omnipresent windows)

View File

@@ -24,8 +24,6 @@ typedef enum TaskState {
extern timeout *urgent_timeout; extern timeout *urgent_timeout;
extern GSList *urgent_list; extern GSList *urgent_list;
// --------------------------------------------------
// global task parameter
typedef struct GlobalTask { typedef struct GlobalTask {
Area area; Area area;
@@ -52,7 +50,10 @@ typedef struct GlobalTask {
gboolean tooltip_enabled; gboolean tooltip_enabled;
} GlobalTask; } GlobalTask;
typedef struct { // Stores information about a task.
// Warning: any dynamically allocated members are shared between the Task instances created for the same window
// (for example, if the task appears on all desktops, there will be a different instance on each desktop's taskbar).
typedef struct Task {
// always start with area // always start with area
Area area; Area area;
@@ -83,11 +84,15 @@ void on_change_task(void *obj);
void get_icon(Task *task); void get_icon(Task *task);
gboolean get_title(Task *task); gboolean get_title(Task *task);
void active_task(); void reset_active_task();
void set_task_state(Task *task, TaskState state); void set_task_state(Task *task, TaskState state);
void set_task_redraw(Task *task); void set_task_redraw(Task *task);
Task *find_active_task(Task *current_task, Task *active_task); // Given a pointer to the task that is currently under the mouse (current_task),
// returns a pointer to the Task for the active window on the same taskbar.
// If not found, returns the current task.
Task *find_active_task(Task *current_task);
Task *next_task(Task *task); Task *next_task(Task *task);
Task *prev_task(Task *task); Task *prev_task(Task *task);

View File

@@ -33,13 +33,13 @@
#include "panel.h" #include "panel.h"
#include "strnatcmp.h" #include "strnatcmp.h"
/* win_to_task_table holds for every Window an array of tasks. Usually the array contains only one /* win_to_task holds for every Window an array of tasks. Usually the array contains only one
element. However for omnipresent windows (windows which are visible in every taskbar) the array element. However for omnipresent windows (windows which are visible in every taskbar) the array
contains to every Task* on each panel a pointer (i.e. GPtrArray.len == server.num_desktops) contains to every Task* on each panel a pointer (i.e. GPtrArray.len == server.num_desktops)
*/ */
GHashTable *win_to_task_table; GHashTable *win_to_task;
Task *task_active; Task *active_task;
Task *task_drag; Task *task_drag;
gboolean taskbar_enabled; gboolean taskbar_enabled;
gboolean taskbar_distribute_size; gboolean taskbar_distribute_size;
@@ -50,12 +50,14 @@ Alignment taskbar_alignment;
guint win_hash(gconstpointer key) guint win_hash(gconstpointer key)
{ {
return (guint) * ((const Window *)key); return *((const Window *)key);
} }
gboolean win_compare(gconstpointer a, gconstpointer b) gboolean win_compare(gconstpointer a, gconstpointer b)
{ {
return (*((const Window *)a) == *((const Window *)b)); return (*((const Window *)a) == *((const Window *)b));
} }
void free_ptr_array(gpointer data) void free_ptr_array(gpointer data)
{ {
g_ptr_array_free(data, 1); g_ptr_array_free(data, 1);
@@ -63,7 +65,7 @@ void free_ptr_array(gpointer data)
void default_taskbar() void default_taskbar()
{ {
win_to_task_table = NULL; win_to_task = NULL;
urgent_timeout = NULL; urgent_timeout = NULL;
urgent_list = NULL; urgent_list = NULL;
taskbar_enabled = 0; taskbar_enabled = 0;
@@ -77,29 +79,25 @@ void default_taskbar()
void cleanup_taskbar() void cleanup_taskbar()
{ {
Panel *panel;
Taskbar *taskbar;
int i, j, k;
cleanup_taskbarname(); cleanup_taskbarname();
if (win_to_task_table) { if (win_to_task) {
while (g_hash_table_size(win_to_task_table)) { while (g_hash_table_size(win_to_task)) {
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
g_hash_table_iter_init(&iter, win_to_task_table); g_hash_table_iter_init(&iter, win_to_task);
if (g_hash_table_iter_next(&iter, &key, &value)) { if (g_hash_table_iter_next(&iter, &key, &value)) {
taskbar_remove_task(key, 0, 0); taskbar_remove_task(key, 0, 0);
} }
} }
g_hash_table_destroy(win_to_task_table); g_hash_table_destroy(win_to_task);
win_to_task_table = NULL; win_to_task = NULL;
} }
for (i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
panel = &panels[i]; Panel *panel = &panels[i];
for (j = 0; j < panel->num_desktops; j++) { for (int j = 0; j < panel->num_desktops; j++) {
taskbar = &panel->taskbar[j]; Taskbar *taskbar = &panel->taskbar[j];
for (k = 0; k < TASKBAR_STATE_COUNT; ++k) { for (int k = 0; k < TASKBAR_STATE_COUNT; ++k) {
if (taskbar->state_pix[k]) if (taskbar->state_pix[k])
XFreePixmap(server.dsp, taskbar->state_pix[k]); XFreePixmap(server.dsp, taskbar->state_pix[k]);
taskbar->state_pix[k] = 0; taskbar->state_pix[k] = 0;
@@ -122,17 +120,16 @@ void cleanup_taskbar()
void init_taskbar() void init_taskbar()
{ {
if (!win_to_task_table) if (!win_to_task)
win_to_task_table = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array); win_to_task = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
task_active = 0; active_task = 0;
task_drag = 0; task_drag = 0;
} }
void init_taskbar_panel(void *p) void init_taskbar_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
int j;
if (!panel->g_taskbar.background[TASKBAR_NORMAL]) { if (!panel->g_taskbar.background[TASKBAR_NORMAL]) {
panel->g_taskbar.background[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, 0); panel->g_taskbar.background[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, 0);
@@ -235,7 +232,7 @@ void init_taskbar_panel(void *p)
panel->g_task.area.height = panel->g_task.maximum_height; panel->g_task.area.height = panel->g_task.maximum_height;
} }
for (j = 0; j < TASK_STATE_COUNT; ++j) { for (int j = 0; j < TASK_STATE_COUNT; ++j) {
if (!panel->g_task.background[j]) if (!panel->g_task.background[j])
panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0); panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0);
if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) { if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) {
@@ -275,7 +272,7 @@ void init_taskbar_panel(void *p)
Taskbar *taskbar; Taskbar *taskbar;
panel->num_desktops = server.num_desktops; panel->num_desktops = server.num_desktops;
panel->taskbar = calloc(server.num_desktops, sizeof(Taskbar)); panel->taskbar = calloc(server.num_desktops, sizeof(Taskbar));
for (j = 0; j < panel->num_desktops; j++) { for (int j = 0; j < panel->num_desktops; j++) {
taskbar = &panel->taskbar[j]; taskbar = &panel->taskbar[j];
memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area)); memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area));
taskbar->desktop = j; taskbar->desktop = j;
@@ -297,32 +294,30 @@ Task *task_get_task(Window win)
GPtrArray *task_group = task_get_tasks(win); GPtrArray *task_group = task_get_tasks(win);
if (task_group) if (task_group)
return g_ptr_array_index(task_group, 0); return g_ptr_array_index(task_group, 0);
else return NULL;
return 0;
} }
GPtrArray *task_get_tasks(Window win) GPtrArray *task_get_tasks(Window win)
{ {
if (win_to_task_table && taskbar_enabled) if (win_to_task && taskbar_enabled)
return g_hash_table_lookup(win_to_task_table, &win); return g_hash_table_lookup(win_to_task, &win);
else return NULL;
return 0;
} }
void task_refresh_tasklist() void task_refresh_tasklist()
{ {
Window *win;
int num_results, i;
if (!taskbar_enabled) if (!taskbar_enabled)
return; return;
win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
int num_results;
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
if (!win) if (!win)
return; return;
GList *win_list = g_hash_table_get_keys(win_to_task_table); GList *win_list = g_hash_table_get_keys(win_to_task);
GList *it; GList *it;
for (it = win_list; it; it = it->next) { for (it = win_list; it; it = it->next) {
int i;
for (i = 0; i < num_results; i++) for (i = 0; i < num_results; i++)
if (*((Window *)it->data) == win[i]) if (*((Window *)it->data) == win[i])
break; break;
@@ -332,7 +327,7 @@ void task_refresh_tasklist()
g_list_free(win_list); g_list_free(win_list);
// Add any new // Add any new
for (i = 0; i < num_results; i++) for (int i = 0; i < num_results; i++)
if (!task_get_task(win[i])) if (!task_get_task(win[i]))
add_task(win[i]); add_task(win[i]);
@@ -351,13 +346,12 @@ gboolean resize_taskbar(void *obj)
{ {
Taskbar *taskbar = (Taskbar *)obj; Taskbar *taskbar = (Taskbar *)obj;
Panel *panel = (Panel *)taskbar->area.panel; Panel *panel = (Panel *)taskbar->area.panel;
int text_width;
// printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy); // printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
if (panel_horizontal) { if (panel_horizontal) {
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width); relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
text_width = panel->g_task.maximum_width; int text_width = panel->g_task.maximum_width;
GList *l = taskbar->area.children; GList *l = taskbar->area.children;
if (taskbarname_enabled) if (taskbarname_enabled)
l = l->next; l = l->next;
@@ -368,23 +362,22 @@ gboolean resize_taskbar(void *obj)
} }
} }
taskbar->text_width = taskbar->text_width =
text_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr; text_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
} else { } else {
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height); relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height);
taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx - taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx -
panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr; panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
} }
return 0; return FALSE;
} }
void on_change_taskbar(void *obj) void on_change_taskbar(void *obj)
{ {
Taskbar *taskbar = (Taskbar *)obj; Taskbar *taskbar = (Taskbar *)obj;
int k;
// reset Pixmap when position/size changed // reset Pixmap when position/size changed
for (k = 0; k < TASKBAR_STATE_COUNT; ++k) { for (int k = 0; k < TASKBAR_STATE_COUNT; ++k) {
if (taskbar->state_pix[k]) if (taskbar->state_pix[k])
XFreePixmap(server.dsp, taskbar->state_pix[k]); XFreePixmap(server.dsp, taskbar->state_pix[k]);
taskbar->state_pix[k] = 0; taskbar->state_pix[k] = 0;
@@ -426,7 +419,7 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state)
if (taskbarname_enabled) if (taskbarname_enabled)
l = l->next; l = l->next;
for (; l; l = l->next) for (; l; l = l->next)
set_task_redraw(l->data); set_task_redraw((Task *)l->data);
} }
} }
panel_refresh = TRUE; panel_refresh = TRUE;
@@ -435,10 +428,9 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state)
void visible_taskbar(void *p) void visible_taskbar(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
int j;
Taskbar *taskbar; Taskbar *taskbar;
for (j = 0; j < panel->num_desktops; j++) { for (int j = 0; j < panel->num_desktops; j++) {
taskbar = &panel->taskbar[j]; taskbar = &panel->taskbar[j];
if (taskbar_mode != MULTI_DESKTOP && taskbar->desktop != server.desktop) { if (taskbar_mode != MULTI_DESKTOP && taskbar->desktop != server.desktop) {
// SINGLE_DESKTOP and not current desktop // SINGLE_DESKTOP and not current desktop
@@ -493,11 +485,10 @@ gint compare_task_centers(Task *a, Task *b, Taskbar *taskbar)
return 1; return 1;
// Compare centers // Compare centers
int a_horiz_c, a_vert_c, b_horiz_c, b_vert_c; int a_horiz_c = a->win_x + a->win_w / 2;
a_horiz_c = a->win_x + a->win_w / 2; int b_horiz_c = b->win_x + b->win_w / 2;
b_horiz_c = b->win_x + b->win_w / 2; int a_vert_c = a->win_y + a->win_h / 2;
a_vert_c = a->win_y + a->win_h / 2; int b_vert_c = b->win_y + b->win_h / 2;
b_vert_c = b->win_y + b->win_h / 2;
if (panel_horizontal) { if (panel_horizontal) {
if (a_horiz_c != b_horiz_c) { if (a_horiz_c != b_horiz_c) {
return a_horiz_c - b_horiz_c; return a_horiz_c - b_horiz_c;
@@ -534,19 +525,18 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
return 0; return 0;
} }
int taskbar_needs_sort(Taskbar *taskbar) gboolean taskbar_needs_sort(Taskbar *taskbar)
{ {
if (taskbar_sort_method == TASKBAR_NOSORT) if (taskbar_sort_method == TASKBAR_NOSORT)
return 0; return FALSE;
GList *i, *j; for (GList *i = taskbar->area.children, *j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
for (i = taskbar->area.children, j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
if (compare_tasks(i->data, j->data, taskbar) > 0) { if (compare_tasks(i->data, j->data, taskbar) > 0) {
return 1; return TRUE;
} }
} }
return 0; return FALSE;
} }
void sort_tasks(Taskbar *taskbar) void sort_tasks(Taskbar *taskbar)
@@ -557,9 +547,9 @@ void sort_tasks(Taskbar *taskbar)
return; return;
taskbar->area.children = g_list_sort_with_data(taskbar->area.children, (GCompareDataFunc)compare_tasks, taskbar); taskbar->area.children = g_list_sort_with_data(taskbar->area.children, (GCompareDataFunc)compare_tasks, taskbar);
taskbar->area.resize_needed = 1; taskbar->area.resize_needed = TRUE;
panel_refresh = TRUE; panel_refresh = TRUE;
((Panel *)taskbar->area.panel)->area.resize_needed = 1; ((Panel *)taskbar->area.panel)->area.resize_needed = TRUE;
} }
void sort_taskbar_for_win(Window win) void sort_taskbar_for_win(Window win)
@@ -569,12 +559,11 @@ void sort_taskbar_for_win(Window win)
GPtrArray *task_group = task_get_tasks(win); GPtrArray *task_group = task_get_tasks(win);
if (task_group) { if (task_group) {
int i;
Task *task0 = g_ptr_array_index(task_group, 0); Task *task0 = g_ptr_array_index(task_group, 0);
if (task0) { if (task0) {
get_window_coordinates(win, &task0->win_x, &task0->win_y, &task0->win_w, &task0->win_h); get_window_coordinates(win, &task0->win_x, &task0->win_y, &task0->win_w, &task0->win_h);
} }
for (i = 0; i < task_group->len; ++i) { for (int i = 0; i < task_group->len; ++i) {
Task *task = g_ptr_array_index(task_group, i); Task *task = g_ptr_array_index(task_group, i);
task->win_x = task0->win_x; task->win_x = task0->win_x;
task->win_y = task0->win_y; task->win_y = task0->win_y;

View File

@@ -23,8 +23,8 @@ typedef enum TaskbarSortMethod {
TASKBAR_SORT_TITLE, TASKBAR_SORT_TITLE,
} TaskbarSortMethod; } TaskbarSortMethod;
extern GHashTable *win_to_task_table; extern GHashTable *win_to_task;
extern Task *task_active; extern Task *active_task;
extern Task *task_drag; extern Task *task_drag;
extern gboolean taskbar_enabled; extern gboolean taskbar_enabled;
extern gboolean taskbar_distribute_size; extern gboolean taskbar_distribute_size;

View File

@@ -113,7 +113,7 @@ void init(int argc, char *argv[])
default_config(); default_config();
default_timeout(); default_timeout();
default_systray(); default_systray();
memset(&server, 0, sizeof(Server_global)); memset(&server, 0, sizeof(server));
#ifdef ENABLE_BATTERY #ifdef ENABLE_BATTERY
default_battery(); default_battery();
#endif #endif
@@ -390,7 +390,7 @@ void window_action(Task *task, int action)
XIconifyWindow(server.dsp, task->win, server.screen); XIconifyWindow(server.dsp, task->win, server.screen);
break; break;
case TOGGLE_ICONIFY: case TOGGLE_ICONIFY:
if (task_active && task->win == task_active->win) if (active_task && task->win == active_task->win)
XIconifyWindow(server.dsp, task->win, server.screen); XIconifyWindow(server.dsp, task->win, server.screen);
else else
activate_window(task->win); activate_window(task->win);
@@ -425,12 +425,12 @@ void window_action(Task *task, int action)
break; break;
case NEXT_TASK: { case NEXT_TASK: {
Task *task1; Task *task1;
task1 = next_task(find_active_task(task, task_active)); task1 = next_task(find_active_task(task));
activate_window(task1->win); activate_window(task1->win);
} break; } break;
case PREV_TASK: { case PREV_TASK: {
Task *task1; Task *task1;
task1 = prev_task(find_active_task(task, task_active)); task1 = prev_task(find_active_task(task));
activate_window(task1->win); activate_window(task1->win);
} }
} }
@@ -544,7 +544,7 @@ void event_button_motion_notify(XEvent *e)
} }
} }
} else { // The event is on another taskbar than the task being dragged } else { // The event is on another taskbar than the task being dragged
if (task_drag->desktop == ALLDESKTOP || taskbar_mode != MULTI_DESKTOP) if (task_drag->desktop == ALL_DESKTOPS || taskbar_mode != MULTI_DESKTOP)
return; return;
Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent; Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent;
@@ -658,18 +658,74 @@ void event_button_release(XEvent *e)
// switch desktop // switch desktop
if (taskbar_mode == MULTI_DESKTOP) { if (taskbar_mode == MULTI_DESKTOP) {
if (taskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT && action != DESKTOP_RIGHT) gboolean diff_desktop = FALSE;
if (taskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT && action != DESKTOP_RIGHT) {
diff_desktop = TRUE;
change_desktop(taskbar->desktop); change_desktop(taskbar->desktop);
}
Task *task = click_task(panel, e->xbutton.x, e->xbutton.y);
if (task) {
if (diff_desktop) {
if (action == TOGGLE_ICONIFY) {
if (!window_is_active(task->win))
activate_window(task->win);
} else {
window_action(task, action);
}
} else {
window_action(task, action);
}
}
} else {
window_action(click_task(panel, e->xbutton.x, e->xbutton.y), action);
} }
// action on task
window_action(click_task(panel, e->xbutton.x, e->xbutton.y), action);
// to keep window below // to keep window below
if (panel_layer == BOTTOM_LAYER) if (panel_layer == BOTTOM_LAYER)
XLowerWindow(server.dsp, panel->main_win); XLowerWindow(server.dsp, panel->main_win);
} }
void update_desktop_names()
{
if (!taskbarname_enabled)
return;
GSList *list = get_desktop_names();
for (int i = 0; i < num_panels; i++) {
int j;
GSList *l;
for (j = 0, l = list; j < panels[i].num_desktops; j++) {
gchar *name;
if (l) {
name = g_strdup(l->data);
l = l->next;
} else {
name = g_strdup_printf("%d", j + 1);
}
Taskbar *taskbar = &panels[i].taskbar[j];
if (strcmp(name, taskbar->bar_name.name) != 0) {
g_free(taskbar->bar_name.name);
taskbar->bar_name.name = name;
taskbar->bar_name.area.resize_needed = 1;
} else {
g_free(name);
}
}
}
for (GSList *l = list; l; l = l->next)
g_free(l->data);
g_slist_free(list);
panel_refresh = TRUE;
}
void update_task_desktop(Task *task)
{
Window win = task->win;
remove_task(task);
task = add_task(win);
reset_active_task();
panel_refresh = TRUE;
}
void event_property_notify(XEvent *e) void event_property_notify(XEvent *e)
{ {
int i; int i;
@@ -686,93 +742,93 @@ void event_property_notify(XEvent *e)
// Change name of desktops // Change name of desktops
else if (at == server.atom._NET_DESKTOP_NAMES) { else if (at == server.atom._NET_DESKTOP_NAMES) {
if (!taskbarname_enabled) update_desktop_names();
return;
GSList *l, *list = get_desktop_names();
int j;
gchar *name;
Taskbar *taskbar;
for (i = 0; i < num_panels; i++) {
for (j = 0, l = list; j < panels[i].num_desktops; j++) {
if (l) {
name = g_strdup(l->data);
l = l->next;
} else
name = g_strdup_printf("%d", j + 1);
taskbar = &panels[i].taskbar[j];
if (strcmp(name, taskbar->bar_name.name) != 0) {
g_free(taskbar->bar_name.name);
taskbar->bar_name.name = name;
taskbar->bar_name.area.resize_needed = 1;
} else
g_free(name);
}
}
for (l = list; l; l = l->next)
g_free(l->data);
g_slist_free(list);
panel_refresh = TRUE;
} }
// Change number of desktops // Change desktops
else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) { else if (at == server.atom._NET_NUMBER_OF_DESKTOPS ||
if (!taskbar_enabled) at == server.atom._NET_DESKTOP_GEOMETRY ||
return; at == server.atom._NET_DESKTOP_VIEWPORT ||
server.num_desktops = server_get_number_of_desktops(); at == server.atom._NET_WORKAREA ||
if (server.num_desktops <= server.desktop) { at == server.atom._NET_CURRENT_DESKTOP) {
server.desktop = server.num_desktops - 1;
}
cleanup_taskbar();
init_taskbar();
for (i = 0; i < num_panels; i++) {
init_taskbar_panel(&panels[i]);
set_panel_items_order(&panels[i]);
visible_taskbar(&panels[i]);
panels[i].area.resize_needed = 1;
}
task_refresh_tasklist();
active_task();
panel_refresh = TRUE;
}
// Change desktop
else if (at == server.atom._NET_CURRENT_DESKTOP) {
if (!taskbar_enabled) if (!taskbar_enabled)
return; return;
int old_num_desktops = server.num_desktops;
int old_desktop = server.desktop; int old_desktop = server.desktop;
server_get_number_of_desktops();
server.desktop = get_current_desktop(); server.desktop = get_current_desktop();
for (i = 0; i < num_panels; i++) { if (old_num_desktops != server.num_desktops) {
Panel *panel = &panels[i]; if (server.num_desktops <= server.desktop) {
set_taskbar_state(&panel->taskbar[old_desktop], TASKBAR_NORMAL); server.desktop = server.num_desktops - 1;
set_taskbar_state(&panel->taskbar[server.desktop], TASKBAR_ACTIVE); }
// check ALLDESKTOP task => resize taskbar cleanup_taskbar();
Taskbar *taskbar; init_taskbar();
Task *task; for (i = 0; i < num_panels; i++) {
if (server.num_desktops > old_desktop) { init_taskbar_panel(&panels[i]);
taskbar = &panel->taskbar[old_desktop]; set_panel_items_order(&panels[i]);
visible_taskbar(&panels[i]);
panels[i].area.resize_needed = 1;
}
task_refresh_tasklist();
reset_active_task();
panel_refresh = TRUE;
} else if (old_desktop != server.desktop) {
for (i = 0; i < num_panels; i++) {
Panel *panel = &panels[i];
set_taskbar_state(&panel->taskbar[old_desktop], TASKBAR_NORMAL);
set_taskbar_state(&panel->taskbar[server.desktop], TASKBAR_ACTIVE);
// check ALL_DESKTOPS task => resize taskbar
Taskbar *taskbar;
if (server.num_desktops > old_desktop) {
taskbar = &panel->taskbar[old_desktop];
GList *l = taskbar->area.children;
if (taskbarname_enabled)
l = l->next;
for (; l; l = l->next) {
Task *task = l->data;
if (task->desktop == ALL_DESKTOPS) {
task->area.on_screen = FALSE;
taskbar->area.resize_needed = 1;
panel_refresh = TRUE;
if (taskbar_mode == MULTI_DESKTOP)
panel->area.resize_needed = 1;
}
}
}
taskbar = &panel->taskbar[server.desktop];
GList *l = taskbar->area.children; GList *l = taskbar->area.children;
if (taskbarname_enabled) if (taskbarname_enabled)
l = l->next; l = l->next;
for (; l; l = l->next) { for (; l; l = l->next) {
task = l->data; Task *task = l->data;
if (task->desktop == ALLDESKTOP) { if (task->desktop == ALL_DESKTOPS) {
task->area.on_screen = FALSE; task->area.on_screen = TRUE;
taskbar->area.resize_needed = 1; taskbar->area.resize_needed = 1;
panel_refresh = TRUE;
if (taskbar_mode == MULTI_DESKTOP) if (taskbar_mode == MULTI_DESKTOP)
panel->area.resize_needed = 1; panel->area.resize_needed = 1;
} }
} }
}
taskbar = &panel->taskbar[server.desktop]; if (server.viewports) {
GList *l = taskbar->area.children; GList *need_update = NULL;
if (taskbarname_enabled)
l = l->next; GHashTableIter iter;
for (; l; l = l->next) { gpointer key, value;
task = l->data;
if (task->desktop == ALLDESKTOP) { g_hash_table_iter_init(&iter, win_to_task);
task->area.on_screen = TRUE; while (g_hash_table_iter_next(&iter, &key, &value)) {
taskbar->area.resize_needed = 1; Window task_win = *(Window *)key;
if (taskbar_mode == MULTI_DESKTOP) Task *task = task_get_task(task_win);
panel->area.resize_needed = 1; if (task) {
int desktop = get_window_desktop(task_win);
if (desktop != task->desktop) {
need_update = g_list_append(need_update, task);
}
}
}
for (l = need_update; l; l = l->next) {
Task *task = l->data;
update_task_desktop(task);
}
} }
} }
} }
@@ -784,7 +840,7 @@ void event_property_notify(XEvent *e)
} }
// Change active // Change active
else if (at == server.atom._NET_ACTIVE_WINDOW) { else if (at == server.atom._NET_ACTIVE_WINDOW) {
active_task(); reset_active_task();
panel_refresh = TRUE; panel_refresh = TRUE;
} else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) { } else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) {
// change Wallpaper // change Wallpaper
@@ -838,7 +894,7 @@ void event_property_notify(XEvent *e)
} }
} else if (at == server.atom.WM_STATE) { } else if (at == server.atom.WM_STATE) {
// Iconic state // Iconic state
TaskState state = (task_active && task->win == task_active->win ? TASK_ACTIVE : TASK_NORMAL); TaskState state = (active_task && task->win == active_task->win ? TASK_ACTIVE : TASK_NORMAL);
if (window_is_iconified(win)) if (window_is_iconified(win))
state = TASK_ICONIFIED; state = TASK_ICONIFIED;
set_task_state(task, state); set_task_state(task, state);
@@ -855,10 +911,7 @@ void event_property_notify(XEvent *e)
// printf(" Window desktop changed %d, %d\n", task->desktop, desktop); // printf(" Window desktop changed %d, %d\n", task->desktop, desktop);
// bug in windowmaker : send unecessary 'desktop changed' when focus changed // bug in windowmaker : send unecessary 'desktop changed' when focus changed
if (desktop != task->desktop) { if (desktop != task->desktop) {
remove_task(task); update_task_desktop(task);
task = add_task(win);
active_task();
panel_refresh = TRUE;
} }
} else if (at == server.atom.WM_HINTS) { } else if (at == server.atom.WM_HINTS) {
XWMHints *wmhints = XGetWMHints(server.dsp, win); XWMHints *wmhints = XGetWMHints(server.dsp, win);
@@ -917,13 +970,23 @@ void event_configure_notify(XEvent *e)
task = add_task(win); task = add_task(win);
if (win == get_active_window()) { if (win == get_active_window()) {
set_task_state(task, TASK_ACTIVE); set_task_state(task, TASK_ACTIVE);
task_active = task; active_task = task;
} }
panel_refresh = TRUE; panel_refresh = TRUE;
} }
} }
} }
if (server.viewports) {
Task *task = task_get_task(win);
if (task) {
int desktop = get_window_desktop(win);
if (task->desktop != desktop) {
update_task_desktop(task);
}
}
}
sort_taskbar_for_win(win); sort_taskbar_for_win(win);
} }

View File

@@ -35,7 +35,7 @@ typedef enum MouseAction {
PREV_TASK PREV_TASK
} MouseAction; } MouseAction;
#define ALLDESKTOP 0xFFFFFFFF #define ALL_DESKTOPS 0xFFFFFFFF
// Copies a file to another path // Copies a file to another path
void copy_file(const char *path_src, const char *path_dest); void copy_file(const char *path_src, const char *path_dest);

View File

@@ -40,11 +40,6 @@ 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_desktop(int desktop)
{
send_event32(server.root_win, server.atom._NET_CURRENT_DESKTOP, desktop, 0, 0);
}
void change_window_desktop(Window win, int desktop) 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);
@@ -113,7 +108,53 @@ gboolean window_is_hidden(Window win)
int get_window_desktop(Window win) int get_window_desktop(Window win)
{ {
return get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL); if (!server.viewports)
return get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
int x, y, w, h;
get_window_coordinates(win, &x, &y, &w, &h);
int desktop = MIN(get_current_desktop(), server.num_desktops - 1);
// 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);
// 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;
}
}
}
if (best_match < 0)
best_match = 0;
// printf("window %lx : viewport %d, (%d, %d)\n", win, best_match+1, x, y);
return best_match;
} }
int get_window_monitor(Window win) int get_window_monitor(Window win)
@@ -128,14 +169,14 @@ int get_window_monitor(Window win)
// There is an ambiguity when a window is right on the edge between screens. // 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. // In that case, prefer the monitor which is on the right and bottom of the window's top-left corner.
for (i = 0; i < server.num_monitors; i++) { for (i = 0; i < server.num_monitors; i++) {
if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width)) if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width) &&
if (y >= server.monitor[i].y && y <= (server.monitor[i].y + server.monitor[i].height)) { y >= server.monitor[i].y && y <= (server.monitor[i].y + server.monitor[i].height)) {
int current_right = x < (server.monitor[i].x + server.monitor[i].width); int current_right = x < (server.monitor[i].x + server.monitor[i].width);
int current_bottom = y < (server.monitor[i].y + server.monitor[i].height); int current_bottom = y < (server.monitor[i].y + server.monitor[i].height);
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
best_match = i; best_match = i;
}
} }
}
} }
if (best_match < 0) if (best_match < 0)
@@ -201,29 +242,6 @@ gboolean window_is_skip_taskbar(Window win)
return FALSE; return FALSE;
} }
GSList *get_desktop_names()
{
int count;
GSList *list = NULL;
gchar *data_ptr = server_get_property(server.root_win, server.atom._NET_DESKTOP_NAMES, server.atom.UTF8_STRING, &count);
if (data_ptr) {
list = g_slist_append(list, g_strdup(data_ptr));
for (int j = 0; j < count - 1; j++) {
if (*(data_ptr + j) == '\0') {
gchar *ptr = (gchar *)data_ptr + j + 1;
list = g_slist_append(list, g_strdup(ptr));
}
}
XFree(data_ptr);
}
return list;
}
int get_current_desktop()
{
return get_property32(server.root_win, server.atom._NET_CURRENT_DESKTOP, XA_CARDINAL);
}
Window get_active_window() 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);

View File

@@ -13,10 +13,6 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
GSList *get_desktop_names();
int get_current_desktop();
void change_desktop(int desktop);
Window get_active_window(); Window get_active_window();
gboolean window_is_iconified(Window win); gboolean window_is_iconified(Window win);