diff --git a/src/panel.c b/src/panel.c index ce3ce83..5b3084d 100644 --- a/src/panel.c +++ b/src/panel.c @@ -258,7 +258,7 @@ void init_panel() } task_refresh_tasklist(); - active_task(); + reset_active_task(); } void init_panel_size_and_position(Panel *panel) @@ -576,7 +576,7 @@ void set_panel_properties(Panel *p) (unsigned char *)&val, 1); - val = ALLDESKTOP; + val = ALL_DESKTOPS; XChangeProperty(server.dsp, p->main_win, server.atom._NET_WM_DESKTOP, diff --git a/src/server.c b/src/server.c index 73f6c89..a0bb220 100644 --- a/src/server.c +++ b/src/server.c @@ -29,7 +29,7 @@ #include "config.h" #include "window.h" -Server_global server; +Server server; 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_GEOMETRY = XInternAtom(server.dsp, "_NET_DESKTOP_GEOMETRY", 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_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); @@ -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() @@ -398,7 +517,7 @@ void get_desktops() // detect number of desktops // wait 15s to leave some time for window manager startup 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) break; sleep(1); diff --git a/src/server.h b/src/server.h index 042aae9..e0f05c8 100644 --- a/src/server.h +++ b/src/server.h @@ -26,6 +26,7 @@ typedef struct Global_atom { Atom _NET_DESKTOP_NAMES; Atom _NET_DESKTOP_GEOMETRY; Atom _NET_DESKTOP_VIEWPORT; + Atom _NET_WORKAREA; Atom _NET_ACTIVE_WINDOW; Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_STATE_SKIP_PAGER; @@ -98,7 +99,14 @@ typedef struct Monitor { gchar **names; } Monitor; -typedef struct { +typedef struct Viewport { + int x; + int y; + int width; + int height; +} Viewport; + +typedef struct Server { Display *dsp; Window root_win; Window composite_manager; @@ -111,6 +119,9 @@ typedef struct { int num_desktops; // number of monitor (without monitor included into another one) 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; int got_root_win; Visual *visual; @@ -125,9 +136,9 @@ typedef struct { SnDisplay *sn_dsp; GTree *pids; #endif // HAVE_SN -} Server_global; +} Server; -extern Server_global server; +extern Server server; // freed memory void cleanup_server(); @@ -147,6 +158,10 @@ void get_root_pixmap(); void get_monitors(); void print_monitors(); 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 diff --git a/src/taskbar/task.c b/src/taskbar/task.c index 15e5ea8..ccdcb69 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -18,22 +18,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **************************************************************************/ -#include -#include -#include +#include #include #include #include -#include #include +#include +#include +#include -#include "window.h" +#include "panel.h" +#include "server.h" #include "task.h" #include "taskbar.h" -#include "server.h" -#include "panel.h" -#include "tooltip.h" #include "timer.h" +#include "tooltip.h" +#include "window.h" timeout *urgent_timeout; GSList *urgent_list; @@ -47,102 +47,99 @@ char *task_get_tooltip(void *obj) Task *add_task(Window win) { if (!win) - return 0; + return NULL; if (window_is_hidden(win)) - return 0; + return NULL; XSelectInput(server.dsp, win, PropertyChangeMask | StructureNotifyMask); XFlush(server.dsp); - int monitor; + int monitor = 0; if (num_panels > 1) { monitor = get_window_monitor(win); if (monitor >= num_panels) monitor = 0; - } else - monitor = 0; + } - Task new_task; - memset(&new_task, 0, sizeof(new_task)); - new_task.area.has_mouse_over_effect = 1; - new_task.area.has_mouse_press_effect = 1; - new_task.win = win; - new_task.desktop = get_window_desktop(win); - new_task.area.panel = &panels[monitor]; - new_task.current_state = window_is_iconified(win) ? TASK_ICONIFIED : TASK_NORMAL; - get_window_coordinates(win, &new_task.win_x, &new_task.win_y, &new_task.win_w, &new_task.win_h); + // TODO why do we add the task only to the panel for the current monitor, without checking hide_task_diff_monitor? + + Task task_template; + memset(&task_template, 0, sizeof(task_template)); + task_template.area.has_mouse_over_effect = TRUE; + task_template.area.has_mouse_press_effect = TRUE; + task_template.win = win; + task_template.desktop = get_window_desktop(win); + 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 // even with task_on_all_desktop and with task_on_all_panel - new_task.title = 0; - int k; - for (k = 0; k < TASK_STATE_COUNT; ++k) { - new_task.icon[k] = 0; - new_task.state_pix[k] = 0; + task_template.title = NULL; + for (int k = 0; k < TASK_STATE_COUNT; ++k) { + task_template.icon[k] = NULL; + task_template.state_pix[k] = 0; } - get_title(&new_task); - get_icon(&new_task); + get_title(&task_template); + get_icon(&task_template); // 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(); - Taskbar *taskbar; - Task *new_task2 = 0; - int j; - for (j = 0; j < panels[monitor].num_desktops; j++) { - if (new_task.desktop != ALLDESKTOP && new_task.desktop != j) + for (int j = 0; j < panels[monitor].num_desktops; j++) { + if (task_template.desktop != ALL_DESKTOPS && task_template.desktop != j) continue; - taskbar = &panels[monitor].taskbar[j]; - new_task2 = calloc(1, sizeof(Task)); - memcpy(&new_task2->area, &panels[monitor].g_task.area, sizeof(Area)); - new_task2->area.parent = taskbar; - new_task2->area.has_mouse_over_effect = 1; - new_task2->area.has_mouse_press_effect = 1; - new_task2->win = new_task.win; - new_task2->desktop = new_task.desktop; - new_task2->win_x = new_task.win_x; - new_task2->win_y = new_task.win_y; - new_task2->win_w = new_task.win_w; - new_task2->win_h = new_task.win_h; - new_task2->current_state = -1; // to update the current state later in set_task_state... - if (new_task2->desktop == ALLDESKTOP && server.desktop != j) { - // hide ALLDESKTOP task on non-current desktop - new_task2->area.on_screen = FALSE; + Taskbar *taskbar = &panels[monitor].taskbar[j]; + Task *task_instance = calloc(1, sizeof(Task)); + memcpy(&task_instance->area, &panels[monitor].g_task.area, sizeof(Area)); + task_instance->area.has_mouse_over_effect = TRUE; + task_instance->area.has_mouse_press_effect = TRUE; + task_instance->win = task_template.win; + task_instance->desktop = task_template.desktop; + task_instance->win_x = task_template.win_x; + task_instance->win_y = task_template.win_y; + task_instance->win_w = task_template.win_w; + task_instance->win_h = task_template.win_h; + task_instance->current_state = -1; // to update the current state later in set_task_state... + if (task_instance->desktop == ALL_DESKTOPS && server.desktop != j) { + // hide ALL_DESKTOPS task on non-current desktop + task_instance->area.on_screen = FALSE; } - new_task2->title = new_task.title; + task_instance->title = task_template.title; if (panels[monitor].g_task.tooltip_enabled) - new_task2->area._get_tooltip_text = task_get_tooltip; - for (k = 0; k < TASK_STATE_COUNT; ++k) { - new_task2->icon[k] = new_task.icon[k]; - new_task2->icon_hover[k] = new_task.icon_hover[k]; - new_task2->icon_press[k] = new_task.icon_press[k]; - new_task2->state_pix[k] = 0; + task_instance->area._get_tooltip_text = task_get_tooltip; + for (int k = 0; k < TASK_STATE_COUNT; ++k) { + task_instance->icon[k] = task_template.icon[k]; + task_instance->icon_hover[k] = task_template.icon_hover[k]; + task_instance->icon_press[k] = task_template.icon_press[k]; + task_instance->state_pix[k] = 0; } - new_task2->icon_width = new_task.icon_width; - new_task2->icon_height = new_task.icon_height; - taskbar->area.children = g_list_append(taskbar->area.children, new_task2); - taskbar->area.resize_needed = 1; - g_ptr_array_add(task_group, new_task2); - // printf("add_task panel %d, desktop %d, task %s\n", i, j, new_task2->title); + task_instance->icon_width = task_template.icon_width; + task_instance->icon_height = task_template.icon_height; + + add_area(&task_instance->area, &taskbar->area); + g_ptr_array_add(task_group, task_instance); + // printf("add_task panel %d, desktop %d, task %s\n", i, j, task_instance->title); } Window *key = calloc(1, sizeof(Window)); - *key = new_task.win; - g_hash_table_insert(win_to_task_table, key, task_group); - set_task_state(new_task2, new_task.current_state); + *key = task_template.win; + g_hash_table_insert(win_to_task, key, task_group); + + set_task_state((Task*)g_ptr_array_index(task_group, 0), task_template.current_state); sort_taskbar_for_win(win); if (taskbar_mode == MULTI_DESKTOP) { - Panel *panel = new_task2->area.panel; - panel->area.resize_needed = 1; + Panel *panel = (Panel*)task_template.area.panel; + panel->area.resize_needed = TRUE; } 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) @@ -162,8 +159,7 @@ void remove_task(Task *task) // printf("remove_task %s %d\n", task->title, task->desktop); if (task->title) free(task->title); - int k; - for (k = 0; k < TASK_STATE_COUNT; ++k) { + for (int k = 0; k < TASK_STATE_COUNT; ++k) { if (task->icon[k]) { imlib_context_set_image(task->icon[k]); imlib_free_image(); @@ -183,13 +179,11 @@ void remove_task(Task *task) XFreePixmap(server.dsp, task->state_pix[k]); } - int i; - Task *task2; - GPtrArray *task_group = g_hash_table_lookup(win_to_task_table, &win); - for (i = 0; i < task_group->len; ++i) { - task2 = g_ptr_array_index(task_group, i); - if (task2 == task_active) - task_active = 0; + GPtrArray *task_group = g_hash_table_lookup(win_to_task, &win); + for (int i = 0; i < task_group->len; ++i) { + Task *task2 = g_ptr_array_index(task_group, i); + if (task2 == active_task) + active_task = 0; if (task2 == task_drag) task_drag = 0; if (g_slist_find(urgent_list, task2)) @@ -197,18 +191,17 @@ void remove_task(Task *task) remove_area((Area *)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) { Panel *panel = task->area.panel; - char *title, *name; 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)) { name = server_get_property(task->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0); if (!name || !strlen(name)) { @@ -216,6 +209,7 @@ gboolean get_title(Task *task) } } + char *title; if (name && strlen(name)) { title = strdup(name); } else { @@ -228,22 +222,22 @@ gboolean get_title(Task *task) // check unecessary title change if (strcmp(task->title, title) == 0) { free(title); - return 0; - } else + return FALSE; + } else { free(task->title); + } } task->title = title; GPtrArray *task_group = task_get_tasks(task->win); if (task_group) { - int i; - for (i = 0; i < task_group->len; ++i) { + for (int i = 0; i < task_group->len; ++i) { Task *task2 = g_ptr_array_index(task_group, i); task2->title = task->title; set_task_redraw(task2); } } - return 1; + return TRUE; } void get_icon(Task *task) @@ -251,7 +245,7 @@ void get_icon(Task *task) Panel *panel = task->area.panel; if (!panel->g_task.icon) return; - int i; + Imlib_Image img = NULL; XWMHints *hints = 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); if (data) { // get ARGB icon @@ -306,9 +301,8 @@ void get_icon(Task *task) // transform icons imlib_context_set_image(img); imlib_image_set_has_alpha(1); - int w, h; - w = imlib_image_get_width(); - h = imlib_image_get_height(); + int w = imlib_image_get_width(); + int h = imlib_image_get_height(); Imlib_Image orig_image = imlib_create_cropped_scaled_image(0, 0, w, h, panel->g_task.icon_size1, panel->g_task.icon_size1); 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; else 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; + } // Render @@ -404,53 +399,46 @@ void draw_task_icon(Task *task, int text_width) 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) 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) { - /* Layout */ - layout = pango_cairo_create_layout(c); + PangoLayout *layout = pango_cairo_create_layout(c); pango_layout_set_font_description(layout, panel->g_task.font_desc); 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_height(layout, panel->g_task.text_height * PANGO_SCALE); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); - /* Center text */ if (panel->g_task.centered) pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); else pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); - pango_layout_get_pixel_size(layout, &width, &height); - - config_text = &panel->g_task.font[task->current_state]; - - double text_posy = (panel->g_task.area.height - height) / 2.0; + int text_height; + pango_layout_get_pixel_size(layout, &text_width, &text_height); + double text_posy = (panel->g_task.area.height - text_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); g_object_unref(layout); } if (panel->g_task.icon) { - draw_task_icon(task, width); + draw_task_icon(task, text_width); } } void on_change_task(void *obj) { - Task *task = obj; + Task *task = (Task *)obj; Panel *panel = (Panel *)task->area.panel; 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); } -// Given a pointer to the active task (active_task) and a pointer -// 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) +Task *find_active_task(Task *current_task) { if (active_task == NULL) return current_task; - Taskbar *taskbar = current_task->area.parent; + Taskbar *taskbar = (Taskbar *)current_task->area.parent; GList *l0 = taskbar->area.children; if (taskbarname_enabled) l0 = l0->next; for (; l0; l0 = l0->next) { - Task *task = l0->data; + Task *task = (Task *)l0->data; if (task->win == active_task->win) return task; } @@ -492,7 +477,7 @@ Task *find_active_task(Task *current_task, Task *active_task) Task *next_task(Task *task) { if (!task) - return 0; + return NULL; Taskbar *taskbar = task->area.parent; @@ -508,7 +493,7 @@ Task *next_task(Task *task) } } - return 0; + return NULL; } Task *prev_task(Task *task) @@ -535,14 +520,14 @@ Task *prev_task(Task *task) task2 = task1; } - return 0; + return NULL; } -void active_task() +void reset_active_task() { - if (task_active) { - set_task_state(task_active, window_is_iconified(task_active->win) ? TASK_ICONIFIED : TASK_NORMAL); - task_active = 0; + if (active_task) { + set_task_state(active_task, window_is_iconified(active_task->win) ? TASK_ICONIFIED : TASK_NORMAL); + active_task = NULL; } Window w1 = get_active_window(); @@ -554,7 +539,7 @@ void active_task() while (XGetTransientForHint(server.dsp, 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) { GPtrArray *task_group = task_get_tasks(task->win); if (task_group) { - int i; - for (i = 0; i < task_group->len; ++i) { + for (int i = 0; i < task_group->len; ++i) { Task *task1 = g_ptr_array_index(task_group, i); task1->current_state = 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)) del_urgent(task1); - int hide = 0; + gboolean hide = FALSE; Taskbar *taskbar = (Taskbar *)task1->area.parent; - if (task->desktop == ALLDESKTOP && server.desktop != taskbar->desktop) { - // Hide ALLDESKTOP task on non-current desktop - hide = 1; + if (task->desktop == ALL_DESKTOPS && server.desktop != taskbar->desktop) { + // Hide ALL_DESKTOPS task on non-current desktop + hide = TRUE; } if (hide_inactive_tasks) { // Show only the active task if (state != TASK_ACTIVE) { - hide = 1; + hide = TRUE; } } if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor && (hide_task_diff_monitor || num_panels > 1)) { - hide = 1; + hide = TRUE; } - if (1 - hide != task1->area.on_screen) { - task1->area.on_screen = TRUE - hide; + if ((!hide) != task1->area.on_screen) { + task1->area.on_screen = !hide; set_task_redraw(task1); Panel *p = (Panel *)task->area.panel; - task->area.resize_needed = 1; - p->taskbar->area.resize_needed = 1; - p->area.resize_needed = 1; + task->area.resize_needed = TRUE; + p->taskbar->area.resize_needed = TRUE; + p->area.resize_needed = TRUE; } } panel_refresh = TRUE; @@ -612,8 +596,7 @@ void set_task_state(Task *task, TaskState state) void set_task_redraw(Task *task) { - int k; - for (k = 0; k < TASK_STATE_COUNT; ++k) { + for (int k = 0; k < TASK_STATE_COUNT; ++k) { if (task->state_pix[k]) XFreePixmap(server.dsp, task->state_pix[k]); task->state_pix[k] = 0; @@ -644,7 +627,7 @@ void add_urgent(Task *task) return; // 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; task = task_get_task(task->win); // always add the first task for a task group (omnipresent windows) diff --git a/src/taskbar/task.h b/src/taskbar/task.h index e8d4cb0..ef7f12e 100644 --- a/src/taskbar/task.h +++ b/src/taskbar/task.h @@ -24,8 +24,6 @@ typedef enum TaskState { extern timeout *urgent_timeout; extern GSList *urgent_list; -// -------------------------------------------------- -// global task parameter typedef struct GlobalTask { Area area; @@ -52,7 +50,10 @@ typedef struct GlobalTask { gboolean tooltip_enabled; } 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 Area area; @@ -83,11 +84,15 @@ void on_change_task(void *obj); void get_icon(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_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 *prev_task(Task *task); diff --git a/src/taskbar/taskbar.c b/src/taskbar/taskbar.c index 389d6b3..6486276 100644 --- a/src/taskbar/taskbar.c +++ b/src/taskbar/taskbar.c @@ -33,13 +33,13 @@ #include "panel.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 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; gboolean taskbar_enabled; gboolean taskbar_distribute_size; @@ -50,12 +50,14 @@ Alignment taskbar_alignment; guint win_hash(gconstpointer key) { - return (guint) * ((const Window *)key); + return *((const Window *)key); } + gboolean win_compare(gconstpointer a, gconstpointer b) { return (*((const Window *)a) == *((const Window *)b)); } + void free_ptr_array(gpointer data) { g_ptr_array_free(data, 1); @@ -63,7 +65,7 @@ void free_ptr_array(gpointer data) void default_taskbar() { - win_to_task_table = NULL; + win_to_task = NULL; urgent_timeout = NULL; urgent_list = NULL; taskbar_enabled = 0; @@ -77,29 +79,25 @@ void default_taskbar() void cleanup_taskbar() { - Panel *panel; - Taskbar *taskbar; - int i, j, k; - cleanup_taskbarname(); - if (win_to_task_table) { - while (g_hash_table_size(win_to_task_table)) { + if (win_to_task) { + while (g_hash_table_size(win_to_task)) { GHashTableIter iter; 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)) { taskbar_remove_task(key, 0, 0); } } - g_hash_table_destroy(win_to_task_table); - win_to_task_table = NULL; + g_hash_table_destroy(win_to_task); + win_to_task = NULL; } - for (i = 0; i < num_panels; i++) { - panel = &panels[i]; - for (j = 0; j < panel->num_desktops; j++) { - taskbar = &panel->taskbar[j]; - for (k = 0; k < TASKBAR_STATE_COUNT; ++k) { + for (int i = 0; i < num_panels; i++) { + Panel *panel = &panels[i]; + for (int j = 0; j < panel->num_desktops; j++) { + Taskbar *taskbar = &panel->taskbar[j]; + for (int k = 0; k < TASKBAR_STATE_COUNT; ++k) { if (taskbar->state_pix[k]) XFreePixmap(server.dsp, taskbar->state_pix[k]); taskbar->state_pix[k] = 0; @@ -122,17 +120,16 @@ void cleanup_taskbar() void init_taskbar() { - if (!win_to_task_table) - win_to_task_table = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array); + if (!win_to_task) + 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; } void init_taskbar_panel(void *p) { Panel *panel = (Panel *)p; - int j; if (!panel->g_taskbar.background[TASKBAR_NORMAL]) { 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; } - for (j = 0; j < TASK_STATE_COUNT; ++j) { + for (int j = 0; j < TASK_STATE_COUNT; ++j) { if (!panel->g_task.background[j]) 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) { @@ -275,7 +272,7 @@ void init_taskbar_panel(void *p) Taskbar *taskbar; panel->num_desktops = server.num_desktops; 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]; memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area)); taskbar->desktop = j; @@ -297,32 +294,30 @@ Task *task_get_task(Window win) GPtrArray *task_group = task_get_tasks(win); if (task_group) return g_ptr_array_index(task_group, 0); - else - return 0; + return NULL; } GPtrArray *task_get_tasks(Window win) { - if (win_to_task_table && taskbar_enabled) - return g_hash_table_lookup(win_to_task_table, &win); - else - return 0; + if (win_to_task && taskbar_enabled) + return g_hash_table_lookup(win_to_task, &win); + return NULL; } void task_refresh_tasklist() { - Window *win; - int num_results, i; - if (!taskbar_enabled) 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) 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; for (it = win_list; it; it = it->next) { + int i; for (i = 0; i < num_results; i++) if (*((Window *)it->data) == win[i]) break; @@ -332,7 +327,7 @@ void task_refresh_tasklist() g_list_free(win_list); // Add any new - for (i = 0; i < num_results; i++) + for (int i = 0; i < num_results; i++) if (!task_get_task(win[i])) add_task(win[i]); @@ -351,13 +346,12 @@ gboolean resize_taskbar(void *obj) { Taskbar *taskbar = (Taskbar *)obj; Panel *panel = (Panel *)taskbar->area.panel; - int text_width; // printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy); if (panel_horizontal) { 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; if (taskbarname_enabled) l = l->next; @@ -368,23 +362,22 @@ gboolean resize_taskbar(void *obj) } } 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 { 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 - panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr; } - return 0; + return FALSE; } void on_change_taskbar(void *obj) { Taskbar *taskbar = (Taskbar *)obj; - int k; // 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]) XFreePixmap(server.dsp, taskbar->state_pix[k]); taskbar->state_pix[k] = 0; @@ -426,7 +419,7 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state) if (taskbarname_enabled) l = l->next; for (; l; l = l->next) - set_task_redraw(l->data); + set_task_redraw((Task *)l->data); } } panel_refresh = TRUE; @@ -435,10 +428,9 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state) void visible_taskbar(void *p) { Panel *panel = (Panel *)p; - int j; Taskbar *taskbar; - for (j = 0; j < panel->num_desktops; j++) { + for (int j = 0; j < panel->num_desktops; j++) { taskbar = &panel->taskbar[j]; if (taskbar_mode != MULTI_DESKTOP && taskbar->desktop != server.desktop) { // SINGLE_DESKTOP and not current desktop @@ -493,11 +485,10 @@ gint compare_task_centers(Task *a, Task *b, Taskbar *taskbar) return 1; // Compare centers - int a_horiz_c, a_vert_c, b_horiz_c, b_vert_c; - a_horiz_c = a->win_x + a->win_w / 2; - b_horiz_c = b->win_x + b->win_w / 2; - a_vert_c = a->win_y + a->win_h / 2; - b_vert_c = b->win_y + b->win_h / 2; + int a_horiz_c = a->win_x + a->win_w / 2; + int b_horiz_c = b->win_x + b->win_w / 2; + int a_vert_c = a->win_y + a->win_h / 2; + int b_vert_c = b->win_y + b->win_h / 2; if (panel_horizontal) { if (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; } -int taskbar_needs_sort(Taskbar *taskbar) +gboolean taskbar_needs_sort(Taskbar *taskbar) { if (taskbar_sort_method == TASKBAR_NOSORT) - return 0; + return FALSE; - GList *i, *j; - for (i = taskbar->area.children, j = i ? i->next : NULL; i && j; i = i->next, j = j->next) { + for (GList *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) { - return 1; + return TRUE; } } - return 0; + return FALSE; } void sort_tasks(Taskbar *taskbar) @@ -557,9 +547,9 @@ void sort_tasks(Taskbar *taskbar) return; 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 *)taskbar->area.panel)->area.resize_needed = 1; + ((Panel *)taskbar->area.panel)->area.resize_needed = TRUE; } 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); if (task_group) { - int i; Task *task0 = g_ptr_array_index(task_group, 0); if (task0) { 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->win_x = task0->win_x; task->win_y = task0->win_y; diff --git a/src/taskbar/taskbar.h b/src/taskbar/taskbar.h index 60c0b26..1e50ccd 100644 --- a/src/taskbar/taskbar.h +++ b/src/taskbar/taskbar.h @@ -23,8 +23,8 @@ typedef enum TaskbarSortMethod { TASKBAR_SORT_TITLE, } TaskbarSortMethod; -extern GHashTable *win_to_task_table; -extern Task *task_active; +extern GHashTable *win_to_task; +extern Task *active_task; extern Task *task_drag; extern gboolean taskbar_enabled; extern gboolean taskbar_distribute_size; diff --git a/src/tint.c b/src/tint.c index 6e40c0e..90655a7 100644 --- a/src/tint.c +++ b/src/tint.c @@ -113,7 +113,7 @@ void init(int argc, char *argv[]) default_config(); default_timeout(); default_systray(); - memset(&server, 0, sizeof(Server_global)); + memset(&server, 0, sizeof(server)); #ifdef ENABLE_BATTERY default_battery(); #endif @@ -390,7 +390,7 @@ void window_action(Task *task, int action) XIconifyWindow(server.dsp, task->win, server.screen); break; 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); else activate_window(task->win); @@ -425,12 +425,12 @@ void window_action(Task *task, int action) break; case NEXT_TASK: { Task *task1; - task1 = next_task(find_active_task(task, task_active)); + task1 = next_task(find_active_task(task)); activate_window(task1->win); } break; case PREV_TASK: { Task *task1; - task1 = prev_task(find_active_task(task, task_active)); + task1 = prev_task(find_active_task(task)); 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 - if (task_drag->desktop == ALLDESKTOP || taskbar_mode != MULTI_DESKTOP) + if (task_drag->desktop == ALL_DESKTOPS || taskbar_mode != MULTI_DESKTOP) return; Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent; @@ -658,18 +658,74 @@ void event_button_release(XEvent *e) // switch 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); + } + 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 if (panel_layer == BOTTOM_LAYER) 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) { int i; @@ -686,93 +742,93 @@ void event_property_notify(XEvent *e) // Change name of desktops else if (at == server.atom._NET_DESKTOP_NAMES) { - if (!taskbarname_enabled) - 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; + update_desktop_names(); } - // Change number of desktops - else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) { - if (!taskbar_enabled) - return; - server.num_desktops = server_get_number_of_desktops(); - if (server.num_desktops <= server.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) { + // Change desktops + else if (at == server.atom._NET_NUMBER_OF_DESKTOPS || + at == server.atom._NET_DESKTOP_GEOMETRY || + at == server.atom._NET_DESKTOP_VIEWPORT || + at == server.atom._NET_WORKAREA || + at == server.atom._NET_CURRENT_DESKTOP) { if (!taskbar_enabled) return; + int old_num_desktops = server.num_desktops; int old_desktop = server.desktop; + server_get_number_of_desktops(); server.desktop = get_current_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 ALLDESKTOP task => resize taskbar - Taskbar *taskbar; - Task *task; - if (server.num_desktops > old_desktop) { - taskbar = &panel->taskbar[old_desktop]; + if (old_num_desktops != server.num_desktops) { + if (server.num_desktops <= server.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(); + 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; if (taskbarname_enabled) l = l->next; for (; l; l = l->next) { - task = l->data; - if (task->desktop == ALLDESKTOP) { - task->area.on_screen = FALSE; + Task *task = l->data; + if (task->desktop == ALL_DESKTOPS) { + task->area.on_screen = TRUE; 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; - if (taskbarname_enabled) - l = l->next; - for (; l; l = l->next) { - task = l->data; - if (task->desktop == ALLDESKTOP) { - task->area.on_screen = TRUE; - taskbar->area.resize_needed = 1; - if (taskbar_mode == MULTI_DESKTOP) - panel->area.resize_needed = 1; + + if (server.viewports) { + GList *need_update = NULL; + + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, win_to_task); + while (g_hash_table_iter_next(&iter, &key, &value)) { + Window task_win = *(Window *)key; + Task *task = task_get_task(task_win); + 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 else if (at == server.atom._NET_ACTIVE_WINDOW) { - active_task(); + reset_active_task(); panel_refresh = TRUE; } else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) { // change Wallpaper @@ -838,7 +894,7 @@ void event_property_notify(XEvent *e) } } else if (at == server.atom.WM_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)) state = TASK_ICONIFIED; 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); // bug in windowmaker : send unecessary 'desktop changed' when focus changed if (desktop != task->desktop) { - remove_task(task); - task = add_task(win); - active_task(); - panel_refresh = TRUE; + update_task_desktop(task); } } else if (at == server.atom.WM_HINTS) { XWMHints *wmhints = XGetWMHints(server.dsp, win); @@ -917,13 +970,23 @@ void event_configure_notify(XEvent *e) task = add_task(win); if (win == get_active_window()) { set_task_state(task, TASK_ACTIVE); - task_active = task; + active_task = task; } 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); } diff --git a/src/util/common.h b/src/util/common.h index ab05815..77bddef 100644 --- a/src/util/common.h +++ b/src/util/common.h @@ -35,7 +35,7 @@ typedef enum MouseAction { PREV_TASK } MouseAction; -#define ALLDESKTOP 0xFFFFFFFF +#define ALL_DESKTOPS 0xFFFFFFFF // Copies a file to another path void copy_file(const char *path_src, const char *path_dest); diff --git a/src/util/window.c b/src/util/window.c index b415eb2..aa11f98 100644 --- a/src/util/window.c +++ b/src/util/window.c @@ -40,11 +40,6 @@ void activate_window(Window win) 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) { 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) { - 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) @@ -128,14 +169,14 @@ int get_window_monitor(Window win) // 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 (i = 0; i < server.num_monitors; i++) { - 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)) { - int current_right = x < (server.monitor[i].x + server.monitor[i].width); - int current_bottom = y < (server.monitor[i].y + server.monitor[i].height); - if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { - best_match = i; - } + if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width) && + 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_bottom = y < (server.monitor[i].y + server.monitor[i].height); + if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { + best_match = i; } + } } if (best_match < 0) @@ -201,29 +242,6 @@ gboolean window_is_skip_taskbar(Window win) 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() { return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW); diff --git a/src/util/window.h b/src/util/window.h index 4841864..88cd3c8 100644 --- a/src/util/window.h +++ b/src/util/window.h @@ -13,10 +13,6 @@ #include #include -GSList *get_desktop_names(); -int get_current_desktop(); -void change_desktop(int desktop); - Window get_active_window(); gboolean window_is_iconified(Window win);