all repos — tint2 @ eb044da8bc865f3ed8fda91986a1cbf8982c9a2f

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Support for NETWM viewports (compiz)
o9000 mrovi9000@gmail.com
commit

eb044da8bc865f3ed8fda91986a1cbf8982c9a2f

parent

4a6937826c2815385baeca8e02365422853dd4e5

M src/panel.csrc/panel.c

@@ -258,7 +258,7 @@ visible_taskbar(p);

} task_refresh_tasklist(); - active_task(); + reset_active_task(); } void init_panel_size_and_position(Panel *panel)

@@ -576,7 +576,7 @@ PropModeReplace,

(unsigned char *)&val, 1); - val = ALLDESKTOP; + val = ALL_DESKTOPS; XChangeProperty(server.dsp, p->main_win, server.atom._NET_WM_DESKTOP,
M src/server.csrc/server.c

@@ -29,7 +29,7 @@ #include "server.h"

#include "config.h" #include "window.h" -Server_global server; +Server server; void server_catch_error(Display *d, XErrorEvent *ev) {

@@ -44,6 +44,7 @@ server.atom._NET_NUMBER_OF_DESKTOPS = XInternAtom(server.dsp, "_NET_NUMBER_OF_DESKTOPS", 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_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 @@ server.monitor[i].height);

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

// 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);
M src/server.hsrc/server.h

@@ -26,6 +26,7 @@ Atom _NET_NUMBER_OF_DESKTOPS;

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

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

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 @@ #ifdef HAVE_SN

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 @@ // detect monitors and desktops

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
M src/taskbar/task.csrc/taskbar/task.c

@@ -18,22 +18,22 @@ * along with this program; if not, write to the Free Software

* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **************************************************************************/ -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> +#include <glib.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <glib.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 "taskbar.h" -#include "server.h" -#include "panel.h" +#include "timer.h" #include "tooltip.h" -#include "timer.h" +#include "window.h" timeout *urgent_timeout; GSList *urgent_list;

@@ -47,102 +47,99 @@

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; + } + + // TODO why do we add the task only to the panel for the current monitor, without checking hide_task_diff_monitor? - 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); + 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 @@ // even with task_on_all_desktop and with task_on_all_panel

// 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 @@ if (task->state_pix[k])

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 @@ del_urgent(task2);

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 @@ name = server_get_property(task->win, server.atom.WM_NAME, XA_STRING, 0);

} } + char *title; if (name && strlen(name)) { title = strdup(name); } else {

@@ -228,22 +222,22 @@ if (task->title) {

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

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 @@ task->icon[k] = 0;

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

// 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 @@ if (panel->g_task.text)

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(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]; + 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; - 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); 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 @@ // reset Pixmap when position/size changed

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 *next_task(Task *task) { if (!task) - return 0; + return NULL; Taskbar *taskbar = task->area.parent;

@@ -508,7 +493,7 @@ return l0->data;

} } - return 0; + return NULL; } Task *prev_task(Task *task)

@@ -535,14 +520,14 @@ }

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

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

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 @@ task1->area.redraw_needed = TRUE;

} 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_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 @@ if (!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)
M src/taskbar/task.hsrc/taskbar/task.h

@@ -24,8 +24,6 @@

extern timeout *urgent_timeout; extern GSList *urgent_list; -// -------------------------------------------------- -// global task parameter typedef struct GlobalTask { Area area;

@@ -52,7 +50,10 @@ int config_font_mask;

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);
M src/taskbar/taskbar.csrc/taskbar/taskbar.c

@@ -33,13 +33,13 @@ #include "window.h"

#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 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 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 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 @@ panel->g_task.area.width = panel->area.width - (2 * panel->g_task.area.posx);

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

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

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

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

} } 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 @@ GList *l = taskbar->area.children;

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 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 @@ if (contained_within(b, a))

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

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 @@ if (!taskbar_needs_sort(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 @@ return;

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;
M src/taskbar/taskbar.hsrc/taskbar/taskbar.h

@@ -23,8 +23,8 @@ TASKBAR_SORT_CENTER,

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;
M src/tint.csrc/tint.c

@@ -113,7 +113,7 @@ // set global data

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 @@ case ICONIFY:

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 @@ activate_window(task->win);

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

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

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

// 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) { + // 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; - 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) { - 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 @@ panel_refresh = TRUE;

} // 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 @@ panel_refresh = TRUE;

} } 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 @@ int desktop = get_window_desktop(win);

// 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,9 +970,19 @@ remove_task(task);

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); } } }
M src/util/common.hsrc/util/common.h

@@ -35,7 +35,7 @@ NEXT_TASK,

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);
M src/util/window.csrc/util/window.c

@@ -40,11 +40,6 @@ {

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

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 match_bottom = 0;

// There is an ambiguity when a window is right on the edge between screens. // In that case, prefer the monitor which is on the right and bottom of the window's top-left corner. for (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)

@@ -199,29 +240,6 @@ }

} XFree(at); 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()
M src/util/window.hsrc/util/window.h

@@ -13,10 +13,6 @@ #include <glib.h>

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