Support for NETWM viewports (compiz)

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

View file

@ -258,7 +258,7 @@ void init_panel()
}
task_refresh_tasklist();
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,

View file

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

View file

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

View file

@ -18,22 +18,22 @@
* 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 "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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,10 +13,6 @@
#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);