Support for NETWM viewports (compiz)
This commit is contained in:
@@ -258,7 +258,7 @@ void init_panel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
task_refresh_tasklist();
|
task_refresh_tasklist();
|
||||||
active_task();
|
reset_active_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_panel_size_and_position(Panel *panel)
|
void init_panel_size_and_position(Panel *panel)
|
||||||
@@ -576,7 +576,7 @@ void set_panel_properties(Panel *p)
|
|||||||
(unsigned char *)&val,
|
(unsigned char *)&val,
|
||||||
1);
|
1);
|
||||||
|
|
||||||
val = ALLDESKTOP;
|
val = ALL_DESKTOPS;
|
||||||
XChangeProperty(server.dsp,
|
XChangeProperty(server.dsp,
|
||||||
p->main_win,
|
p->main_win,
|
||||||
server.atom._NET_WM_DESKTOP,
|
server.atom._NET_WM_DESKTOP,
|
||||||
|
|||||||
127
src/server.c
127
src/server.c
@@ -29,7 +29,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
Server_global server;
|
Server server;
|
||||||
|
|
||||||
void server_catch_error(Display *d, XErrorEvent *ev)
|
void server_catch_error(Display *d, XErrorEvent *ev)
|
||||||
{
|
{
|
||||||
@@ -44,6 +44,7 @@ void server_init_atoms()
|
|||||||
server.atom._NET_DESKTOP_NAMES = XInternAtom(server.dsp, "_NET_DESKTOP_NAMES", False);
|
server.atom._NET_DESKTOP_NAMES = XInternAtom(server.dsp, "_NET_DESKTOP_NAMES", False);
|
||||||
server.atom._NET_DESKTOP_GEOMETRY = XInternAtom(server.dsp, "_NET_DESKTOP_GEOMETRY", False);
|
server.atom._NET_DESKTOP_GEOMETRY = XInternAtom(server.dsp, "_NET_DESKTOP_GEOMETRY", False);
|
||||||
server.atom._NET_DESKTOP_VIEWPORT = XInternAtom(server.dsp, "_NET_DESKTOP_VIEWPORT", False);
|
server.atom._NET_DESKTOP_VIEWPORT = XInternAtom(server.dsp, "_NET_DESKTOP_VIEWPORT", False);
|
||||||
|
server.atom._NET_WORKAREA = XInternAtom(server.dsp, "_NET_WORKAREA", False);
|
||||||
server.atom._NET_ACTIVE_WINDOW = XInternAtom(server.dsp, "_NET_ACTIVE_WINDOW", False);
|
server.atom._NET_ACTIVE_WINDOW = XInternAtom(server.dsp, "_NET_ACTIVE_WINDOW", False);
|
||||||
server.atom._NET_WM_WINDOW_TYPE = XInternAtom(server.dsp, "_NET_WM_WINDOW_TYPE", False);
|
server.atom._NET_WM_WINDOW_TYPE = XInternAtom(server.dsp, "_NET_WM_WINDOW_TYPE", False);
|
||||||
server.atom._NET_WM_STATE_SKIP_PAGER = XInternAtom(server.dsp, "_NET_WM_STATE_SKIP_PAGER", False);
|
server.atom._NET_WM_STATE_SKIP_PAGER = XInternAtom(server.dsp, "_NET_WM_STATE_SKIP_PAGER", False);
|
||||||
@@ -388,9 +389,127 @@ void print_monitors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int server_get_number_of_desktops()
|
void server_get_number_of_desktops()
|
||||||
{
|
{
|
||||||
return get_property32(server.root_win, server.atom._NET_NUMBER_OF_DESKTOPS, XA_CARDINAL);
|
if (server.viewports) {
|
||||||
|
free(server.viewports);
|
||||||
|
server.viewports = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.num_desktops = get_property32(server.root_win, server.atom._NET_NUMBER_OF_DESKTOPS, XA_CARDINAL);
|
||||||
|
if (server.num_desktops > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int num_results;
|
||||||
|
long *work_area_size = server_get_property(server.root_win, server.atom._NET_WORKAREA, XA_CARDINAL, &num_results);
|
||||||
|
if (!work_area_size)
|
||||||
|
return;
|
||||||
|
int work_area_width = work_area_size[0] + work_area_size[2];
|
||||||
|
int work_area_height = work_area_size[1] + work_area_size[3];
|
||||||
|
XFree(work_area_size);
|
||||||
|
|
||||||
|
long *x_screen_size = server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
|
||||||
|
if (!x_screen_size)
|
||||||
|
return;
|
||||||
|
int x_screen_width = x_screen_size[0];
|
||||||
|
int x_screen_height = x_screen_size[1];
|
||||||
|
XFree(x_screen_size);
|
||||||
|
|
||||||
|
int num_viewports = MAX(x_screen_width / work_area_width, 1) * MAX(x_screen_height / work_area_height, 1);
|
||||||
|
if (num_viewports <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
server.viewports = calloc(num_viewports, sizeof(Viewport));
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < MAX(x_screen_height / work_area_height, 1); i++) {
|
||||||
|
for (int j = 0; j < MAX(x_screen_width / work_area_width, 1); j++) {
|
||||||
|
server.viewports[k].x = j * work_area_width;
|
||||||
|
server.viewports[k].y = i * work_area_height;
|
||||||
|
server.viewports[k].width = work_area_width;
|
||||||
|
server.viewports[k].height = work_area_height;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.num_desktops = num_viewports;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList *get_desktop_names()
|
||||||
|
{
|
||||||
|
if (server.viewports) {
|
||||||
|
GSList *list = NULL;
|
||||||
|
for (int j = 0; j < server.num_desktops; j++) {
|
||||||
|
list = g_slist_append(list, g_strdup_printf("%d", j + 1));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count;
|
||||||
|
GSList *list = NULL;
|
||||||
|
gchar *data_ptr = server_get_property(server.root_win, server.atom._NET_DESKTOP_NAMES, server.atom.UTF8_STRING, &count);
|
||||||
|
if (data_ptr) {
|
||||||
|
list = g_slist_append(list, g_strdup(data_ptr));
|
||||||
|
for (int j = 0; j < count - 1; j++) {
|
||||||
|
if (*(data_ptr + j) == '\0') {
|
||||||
|
gchar *ptr = (gchar *)data_ptr + j + 1;
|
||||||
|
list = g_slist_append(list, g_strdup(ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XFree(data_ptr);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_current_desktop()
|
||||||
|
{
|
||||||
|
if (!server.viewports)
|
||||||
|
return get_property32(server.root_win, server.atom._NET_CURRENT_DESKTOP, XA_CARDINAL);
|
||||||
|
|
||||||
|
int num_results;
|
||||||
|
long *work_area_size = server_get_property(server.root_win, server.atom._NET_WORKAREA, XA_CARDINAL, &num_results);
|
||||||
|
if (!work_area_size)
|
||||||
|
return 0;
|
||||||
|
int work_area_width = work_area_size[0] + work_area_size[2];
|
||||||
|
int work_area_height = work_area_size[1] + work_area_size[3];
|
||||||
|
XFree(work_area_size);
|
||||||
|
|
||||||
|
if (work_area_width <= 0 || work_area_height <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
long *viewport = server_get_property(server.root_win, server.atom._NET_DESKTOP_VIEWPORT, XA_CARDINAL, &num_results);
|
||||||
|
if (!viewport)
|
||||||
|
return 0;
|
||||||
|
int viewport_x = viewport[0];
|
||||||
|
int viewport_y = viewport[1];
|
||||||
|
XFree(viewport);
|
||||||
|
|
||||||
|
long *x_screen_size = server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
|
||||||
|
if (!x_screen_size)
|
||||||
|
return 0;
|
||||||
|
int x_screen_width = x_screen_size[0];
|
||||||
|
XFree(x_screen_size);
|
||||||
|
|
||||||
|
int ncols = x_screen_width / work_area_width;
|
||||||
|
|
||||||
|
// fprintf(stderr, "\n");
|
||||||
|
// fprintf(stderr, "Work area size: %d x %d\n", work_area_width, work_area_height);
|
||||||
|
// fprintf(stderr, "Viewport pos: %d x %d\n", viewport_x, viewport_y);
|
||||||
|
// fprintf(stderr, "Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x / work_area_width);
|
||||||
|
|
||||||
|
return (viewport_y / work_area_height) * ncols + viewport_x / work_area_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_desktop(int desktop)
|
||||||
|
{
|
||||||
|
if (!server.viewports) {
|
||||||
|
send_event32(server.root_win, server.atom._NET_CURRENT_DESKTOP, desktop, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_event32(server.root_win,
|
||||||
|
server.atom._NET_DESKTOP_VIEWPORT,
|
||||||
|
server.viewports[desktop].x,
|
||||||
|
server.viewports[desktop].y,
|
||||||
|
0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_desktops()
|
void get_desktops()
|
||||||
@@ -398,7 +517,7 @@ void get_desktops()
|
|||||||
// detect number of desktops
|
// detect number of desktops
|
||||||
// wait 15s to leave some time for window manager startup
|
// wait 15s to leave some time for window manager startup
|
||||||
for (int i = 0; i < 15; i++) {
|
for (int i = 0; i < 15; i++) {
|
||||||
server.num_desktops = server_get_number_of_desktops();
|
server_get_number_of_desktops();
|
||||||
if (server.num_desktops > 0)
|
if (server.num_desktops > 0)
|
||||||
break;
|
break;
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|||||||
23
src/server.h
23
src/server.h
@@ -26,6 +26,7 @@ typedef struct Global_atom {
|
|||||||
Atom _NET_DESKTOP_NAMES;
|
Atom _NET_DESKTOP_NAMES;
|
||||||
Atom _NET_DESKTOP_GEOMETRY;
|
Atom _NET_DESKTOP_GEOMETRY;
|
||||||
Atom _NET_DESKTOP_VIEWPORT;
|
Atom _NET_DESKTOP_VIEWPORT;
|
||||||
|
Atom _NET_WORKAREA;
|
||||||
Atom _NET_ACTIVE_WINDOW;
|
Atom _NET_ACTIVE_WINDOW;
|
||||||
Atom _NET_WM_WINDOW_TYPE;
|
Atom _NET_WM_WINDOW_TYPE;
|
||||||
Atom _NET_WM_STATE_SKIP_PAGER;
|
Atom _NET_WM_STATE_SKIP_PAGER;
|
||||||
@@ -98,7 +99,14 @@ typedef struct Monitor {
|
|||||||
gchar **names;
|
gchar **names;
|
||||||
} Monitor;
|
} Monitor;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Viewport {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} Viewport;
|
||||||
|
|
||||||
|
typedef struct Server {
|
||||||
Display *dsp;
|
Display *dsp;
|
||||||
Window root_win;
|
Window root_win;
|
||||||
Window composite_manager;
|
Window composite_manager;
|
||||||
@@ -111,6 +119,9 @@ typedef struct {
|
|||||||
int num_desktops;
|
int num_desktops;
|
||||||
// number of monitor (without monitor included into another one)
|
// number of monitor (without monitor included into another one)
|
||||||
int num_monitors;
|
int num_monitors;
|
||||||
|
// Non-null only if WM uses viewports (compiz) and number of viewports > 1.
|
||||||
|
// In that case there are num_desktops viewports.
|
||||||
|
Viewport *viewports;
|
||||||
Monitor *monitor;
|
Monitor *monitor;
|
||||||
int got_root_win;
|
int got_root_win;
|
||||||
Visual *visual;
|
Visual *visual;
|
||||||
@@ -125,9 +136,9 @@ typedef struct {
|
|||||||
SnDisplay *sn_dsp;
|
SnDisplay *sn_dsp;
|
||||||
GTree *pids;
|
GTree *pids;
|
||||||
#endif // HAVE_SN
|
#endif // HAVE_SN
|
||||||
} Server_global;
|
} Server;
|
||||||
|
|
||||||
extern Server_global server;
|
extern Server server;
|
||||||
|
|
||||||
// freed memory
|
// freed memory
|
||||||
void cleanup_server();
|
void cleanup_server();
|
||||||
@@ -147,6 +158,10 @@ void get_root_pixmap();
|
|||||||
void get_monitors();
|
void get_monitors();
|
||||||
void print_monitors();
|
void print_monitors();
|
||||||
void get_desktops();
|
void get_desktops();
|
||||||
int server_get_number_of_desktops();
|
void server_get_number_of_desktops();
|
||||||
|
GSList *get_desktop_names();
|
||||||
|
int get_current_desktop();
|
||||||
|
void change_desktop(int desktop);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,22 +18,22 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <glib.h>
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <glib.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
#include "window.h"
|
#include "panel.h"
|
||||||
|
#include "server.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "taskbar.h"
|
#include "taskbar.h"
|
||||||
#include "server.h"
|
|
||||||
#include "panel.h"
|
|
||||||
#include "tooltip.h"
|
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "tooltip.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
timeout *urgent_timeout;
|
timeout *urgent_timeout;
|
||||||
GSList *urgent_list;
|
GSList *urgent_list;
|
||||||
@@ -47,102 +47,99 @@ char *task_get_tooltip(void *obj)
|
|||||||
Task *add_task(Window win)
|
Task *add_task(Window win)
|
||||||
{
|
{
|
||||||
if (!win)
|
if (!win)
|
||||||
return 0;
|
return NULL;
|
||||||
if (window_is_hidden(win))
|
if (window_is_hidden(win))
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
XSelectInput(server.dsp, win, PropertyChangeMask | StructureNotifyMask);
|
XSelectInput(server.dsp, win, PropertyChangeMask | StructureNotifyMask);
|
||||||
XFlush(server.dsp);
|
XFlush(server.dsp);
|
||||||
|
|
||||||
int monitor;
|
int monitor = 0;
|
||||||
if (num_panels > 1) {
|
if (num_panels > 1) {
|
||||||
monitor = get_window_monitor(win);
|
monitor = get_window_monitor(win);
|
||||||
if (monitor >= num_panels)
|
if (monitor >= num_panels)
|
||||||
monitor = 0;
|
monitor = 0;
|
||||||
} else
|
}
|
||||||
monitor = 0;
|
|
||||||
|
|
||||||
Task new_task;
|
// TODO why do we add the task only to the panel for the current monitor, without checking hide_task_diff_monitor?
|
||||||
memset(&new_task, 0, sizeof(new_task));
|
|
||||||
new_task.area.has_mouse_over_effect = 1;
|
Task task_template;
|
||||||
new_task.area.has_mouse_press_effect = 1;
|
memset(&task_template, 0, sizeof(task_template));
|
||||||
new_task.win = win;
|
task_template.area.has_mouse_over_effect = TRUE;
|
||||||
new_task.desktop = get_window_desktop(win);
|
task_template.area.has_mouse_press_effect = TRUE;
|
||||||
new_task.area.panel = &panels[monitor];
|
task_template.win = win;
|
||||||
new_task.current_state = window_is_iconified(win) ? TASK_ICONIFIED : TASK_NORMAL;
|
task_template.desktop = get_window_desktop(win);
|
||||||
get_window_coordinates(win, &new_task.win_x, &new_task.win_y, &new_task.win_w, &new_task.win_h);
|
task_template.area.panel = &panels[monitor];
|
||||||
|
task_template.current_state = window_is_iconified(win) ? TASK_ICONIFIED : TASK_NORMAL;
|
||||||
|
get_window_coordinates(win, &task_template.win_x, &task_template.win_y, &task_template.win_w, &task_template.win_h);
|
||||||
|
|
||||||
// allocate only one title and one icon
|
// allocate only one title and one icon
|
||||||
// even with task_on_all_desktop and with task_on_all_panel
|
// even with task_on_all_desktop and with task_on_all_panel
|
||||||
new_task.title = 0;
|
task_template.title = NULL;
|
||||||
int k;
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
for (k = 0; k < TASK_STATE_COUNT; ++k) {
|
task_template.icon[k] = NULL;
|
||||||
new_task.icon[k] = 0;
|
task_template.state_pix[k] = 0;
|
||||||
new_task.state_pix[k] = 0;
|
|
||||||
}
|
}
|
||||||
get_title(&new_task);
|
get_title(&task_template);
|
||||||
get_icon(&new_task);
|
get_icon(&task_template);
|
||||||
|
|
||||||
// printf("new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor);
|
// printf("new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor);
|
||||||
|
|
||||||
GPtrArray *task_group = g_ptr_array_new();
|
GPtrArray *task_group = g_ptr_array_new();
|
||||||
Taskbar *taskbar;
|
for (int j = 0; j < panels[monitor].num_desktops; j++) {
|
||||||
Task *new_task2 = 0;
|
if (task_template.desktop != ALL_DESKTOPS && task_template.desktop != j)
|
||||||
int j;
|
|
||||||
for (j = 0; j < panels[monitor].num_desktops; j++) {
|
|
||||||
if (new_task.desktop != ALLDESKTOP && new_task.desktop != j)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
taskbar = &panels[monitor].taskbar[j];
|
Taskbar *taskbar = &panels[monitor].taskbar[j];
|
||||||
new_task2 = calloc(1, sizeof(Task));
|
Task *task_instance = calloc(1, sizeof(Task));
|
||||||
memcpy(&new_task2->area, &panels[monitor].g_task.area, sizeof(Area));
|
memcpy(&task_instance->area, &panels[monitor].g_task.area, sizeof(Area));
|
||||||
new_task2->area.parent = taskbar;
|
task_instance->area.has_mouse_over_effect = TRUE;
|
||||||
new_task2->area.has_mouse_over_effect = 1;
|
task_instance->area.has_mouse_press_effect = TRUE;
|
||||||
new_task2->area.has_mouse_press_effect = 1;
|
task_instance->win = task_template.win;
|
||||||
new_task2->win = new_task.win;
|
task_instance->desktop = task_template.desktop;
|
||||||
new_task2->desktop = new_task.desktop;
|
task_instance->win_x = task_template.win_x;
|
||||||
new_task2->win_x = new_task.win_x;
|
task_instance->win_y = task_template.win_y;
|
||||||
new_task2->win_y = new_task.win_y;
|
task_instance->win_w = task_template.win_w;
|
||||||
new_task2->win_w = new_task.win_w;
|
task_instance->win_h = task_template.win_h;
|
||||||
new_task2->win_h = new_task.win_h;
|
task_instance->current_state = -1; // to update the current state later in set_task_state...
|
||||||
new_task2->current_state = -1; // to update the current state later in set_task_state...
|
if (task_instance->desktop == ALL_DESKTOPS && server.desktop != j) {
|
||||||
if (new_task2->desktop == ALLDESKTOP && server.desktop != j) {
|
// hide ALL_DESKTOPS task on non-current desktop
|
||||||
// hide ALLDESKTOP task on non-current desktop
|
task_instance->area.on_screen = FALSE;
|
||||||
new_task2->area.on_screen = FALSE;
|
|
||||||
}
|
}
|
||||||
new_task2->title = new_task.title;
|
task_instance->title = task_template.title;
|
||||||
if (panels[monitor].g_task.tooltip_enabled)
|
if (panels[monitor].g_task.tooltip_enabled)
|
||||||
new_task2->area._get_tooltip_text = task_get_tooltip;
|
task_instance->area._get_tooltip_text = task_get_tooltip;
|
||||||
for (k = 0; k < TASK_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
new_task2->icon[k] = new_task.icon[k];
|
task_instance->icon[k] = task_template.icon[k];
|
||||||
new_task2->icon_hover[k] = new_task.icon_hover[k];
|
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
||||||
new_task2->icon_press[k] = new_task.icon_press[k];
|
task_instance->icon_press[k] = task_template.icon_press[k];
|
||||||
new_task2->state_pix[k] = 0;
|
task_instance->state_pix[k] = 0;
|
||||||
}
|
}
|
||||||
new_task2->icon_width = new_task.icon_width;
|
task_instance->icon_width = task_template.icon_width;
|
||||||
new_task2->icon_height = new_task.icon_height;
|
task_instance->icon_height = task_template.icon_height;
|
||||||
taskbar->area.children = g_list_append(taskbar->area.children, new_task2);
|
|
||||||
taskbar->area.resize_needed = 1;
|
add_area(&task_instance->area, &taskbar->area);
|
||||||
g_ptr_array_add(task_group, new_task2);
|
g_ptr_array_add(task_group, task_instance);
|
||||||
// printf("add_task panel %d, desktop %d, task %s\n", i, j, new_task2->title);
|
// printf("add_task panel %d, desktop %d, task %s\n", i, j, task_instance->title);
|
||||||
}
|
}
|
||||||
Window *key = calloc(1, sizeof(Window));
|
Window *key = calloc(1, sizeof(Window));
|
||||||
*key = new_task.win;
|
*key = task_template.win;
|
||||||
g_hash_table_insert(win_to_task_table, key, task_group);
|
g_hash_table_insert(win_to_task, key, task_group);
|
||||||
set_task_state(new_task2, new_task.current_state);
|
|
||||||
|
set_task_state((Task*)g_ptr_array_index(task_group, 0), task_template.current_state);
|
||||||
|
|
||||||
sort_taskbar_for_win(win);
|
sort_taskbar_for_win(win);
|
||||||
|
|
||||||
if (taskbar_mode == MULTI_DESKTOP) {
|
if (taskbar_mode == MULTI_DESKTOP) {
|
||||||
Panel *panel = new_task2->area.panel;
|
Panel *panel = (Panel*)task_template.area.panel;
|
||||||
panel->area.resize_needed = 1;
|
panel->area.resize_needed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window_is_urgent(win)) {
|
if (window_is_urgent(win)) {
|
||||||
add_urgent(new_task2);
|
add_urgent((Task*)g_ptr_array_index(task_group, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_task2;
|
return (Task*)g_ptr_array_index(task_group, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_task(Task *task)
|
void remove_task(Task *task)
|
||||||
@@ -162,8 +159,7 @@ void remove_task(Task *task)
|
|||||||
// printf("remove_task %s %d\n", task->title, task->desktop);
|
// printf("remove_task %s %d\n", task->title, task->desktop);
|
||||||
if (task->title)
|
if (task->title)
|
||||||
free(task->title);
|
free(task->title);
|
||||||
int k;
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
for (k = 0; k < TASK_STATE_COUNT; ++k) {
|
|
||||||
if (task->icon[k]) {
|
if (task->icon[k]) {
|
||||||
imlib_context_set_image(task->icon[k]);
|
imlib_context_set_image(task->icon[k]);
|
||||||
imlib_free_image();
|
imlib_free_image();
|
||||||
@@ -183,13 +179,11 @@ void remove_task(Task *task)
|
|||||||
XFreePixmap(server.dsp, task->state_pix[k]);
|
XFreePixmap(server.dsp, task->state_pix[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
GPtrArray *task_group = g_hash_table_lookup(win_to_task, &win);
|
||||||
Task *task2;
|
for (int i = 0; i < task_group->len; ++i) {
|
||||||
GPtrArray *task_group = g_hash_table_lookup(win_to_task_table, &win);
|
Task *task2 = g_ptr_array_index(task_group, i);
|
||||||
for (i = 0; i < task_group->len; ++i) {
|
if (task2 == active_task)
|
||||||
task2 = g_ptr_array_index(task_group, i);
|
active_task = 0;
|
||||||
if (task2 == task_active)
|
|
||||||
task_active = 0;
|
|
||||||
if (task2 == task_drag)
|
if (task2 == task_drag)
|
||||||
task_drag = 0;
|
task_drag = 0;
|
||||||
if (g_slist_find(urgent_list, task2))
|
if (g_slist_find(urgent_list, task2))
|
||||||
@@ -197,18 +191,17 @@ void remove_task(Task *task)
|
|||||||
remove_area((Area *)task2);
|
remove_area((Area *)task2);
|
||||||
free(task2);
|
free(task2);
|
||||||
}
|
}
|
||||||
g_hash_table_remove(win_to_task_table, &win);
|
g_hash_table_remove(win_to_task, &win);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean get_title(Task *task)
|
gboolean get_title(Task *task)
|
||||||
{
|
{
|
||||||
Panel *panel = task->area.panel;
|
Panel *panel = task->area.panel;
|
||||||
char *title, *name;
|
|
||||||
|
|
||||||
if (!panel->g_task.text && !panel->g_task.tooltip_enabled && taskbar_sort_method != TASKBAR_SORT_TITLE)
|
if (!panel->g_task.text && !panel->g_task.tooltip_enabled && taskbar_sort_method != TASKBAR_SORT_TITLE)
|
||||||
return 0;
|
return FALSE;
|
||||||
|
|
||||||
name = server_get_property(task->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
|
char *name = server_get_property(task->win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
|
||||||
if (!name || !strlen(name)) {
|
if (!name || !strlen(name)) {
|
||||||
name = server_get_property(task->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0);
|
name = server_get_property(task->win, server.atom._NET_WM_NAME, server.atom.UTF8_STRING, 0);
|
||||||
if (!name || !strlen(name)) {
|
if (!name || !strlen(name)) {
|
||||||
@@ -216,6 +209,7 @@ gboolean get_title(Task *task)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *title;
|
||||||
if (name && strlen(name)) {
|
if (name && strlen(name)) {
|
||||||
title = strdup(name);
|
title = strdup(name);
|
||||||
} else {
|
} else {
|
||||||
@@ -228,22 +222,22 @@ gboolean get_title(Task *task)
|
|||||||
// check unecessary title change
|
// check unecessary title change
|
||||||
if (strcmp(task->title, title) == 0) {
|
if (strcmp(task->title, title) == 0) {
|
||||||
free(title);
|
free(title);
|
||||||
return 0;
|
return FALSE;
|
||||||
} else
|
} else {
|
||||||
free(task->title);
|
free(task->title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task->title = title;
|
task->title = title;
|
||||||
GPtrArray *task_group = task_get_tasks(task->win);
|
GPtrArray *task_group = task_get_tasks(task->win);
|
||||||
if (task_group) {
|
if (task_group) {
|
||||||
int i;
|
for (int i = 0; i < task_group->len; ++i) {
|
||||||
for (i = 0; i < task_group->len; ++i) {
|
|
||||||
Task *task2 = g_ptr_array_index(task_group, i);
|
Task *task2 = g_ptr_array_index(task_group, i);
|
||||||
task2->title = task->title;
|
task2->title = task->title;
|
||||||
set_task_redraw(task2);
|
set_task_redraw(task2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_icon(Task *task)
|
void get_icon(Task *task)
|
||||||
@@ -251,7 +245,7 @@ void get_icon(Task *task)
|
|||||||
Panel *panel = task->area.panel;
|
Panel *panel = task->area.panel;
|
||||||
if (!panel->g_task.icon)
|
if (!panel->g_task.icon)
|
||||||
return;
|
return;
|
||||||
int i;
|
|
||||||
Imlib_Image img = NULL;
|
Imlib_Image img = NULL;
|
||||||
XWMHints *hints = 0;
|
XWMHints *hints = 0;
|
||||||
gulong *data = 0;
|
gulong *data = 0;
|
||||||
@@ -264,6 +258,7 @@ void get_icon(Task *task)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &i);
|
data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &i);
|
||||||
if (data) {
|
if (data) {
|
||||||
// get ARGB icon
|
// get ARGB icon
|
||||||
@@ -306,9 +301,8 @@ void get_icon(Task *task)
|
|||||||
// transform icons
|
// transform icons
|
||||||
imlib_context_set_image(img);
|
imlib_context_set_image(img);
|
||||||
imlib_image_set_has_alpha(1);
|
imlib_image_set_has_alpha(1);
|
||||||
int w, h;
|
int w = imlib_image_get_width();
|
||||||
w = imlib_image_get_width();
|
int h = imlib_image_get_height();
|
||||||
h = imlib_image_get_height();
|
|
||||||
Imlib_Image orig_image =
|
Imlib_Image orig_image =
|
||||||
imlib_create_cropped_scaled_image(0, 0, w, h, panel->g_task.icon_size1, panel->g_task.icon_size1);
|
imlib_create_cropped_scaled_image(0, 0, w, h, panel->g_task.icon_size1, panel->g_task.icon_size1);
|
||||||
imlib_free_image();
|
imlib_free_image();
|
||||||
@@ -380,8 +374,9 @@ void draw_task_icon(Task *task, int text_width)
|
|||||||
pos_x = (task->area.width - text_width - panel->g_task.icon_size1) / 2;
|
pos_x = (task->area.width - text_width - panel->g_task.icon_size1) / 2;
|
||||||
else
|
else
|
||||||
pos_x = (task->area.width - panel->g_task.icon_size1) / 2;
|
pos_x = (task->area.width - panel->g_task.icon_size1) / 2;
|
||||||
} else
|
} else {
|
||||||
pos_x = panel->g_task.area.paddingxlr + task->area.bg->border.width;
|
pos_x = panel->g_task.area.paddingxlr + task->area.bg->border.width;
|
||||||
|
}
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
@@ -404,53 +399,46 @@ void draw_task_icon(Task *task, int text_width)
|
|||||||
|
|
||||||
void draw_task(void *obj, cairo_t *c)
|
void draw_task(void *obj, cairo_t *c)
|
||||||
{
|
{
|
||||||
Task *task = obj;
|
Task *task = (Task *)obj;
|
||||||
|
Panel *panel = (Panel *)task->area.panel;
|
||||||
|
|
||||||
if (!panel_config.mouse_effects)
|
if (!panel_config.mouse_effects)
|
||||||
task->state_pix[task->current_state] = task->area.pix;
|
task->state_pix[task->current_state] = task->area.pix;
|
||||||
PangoLayout *layout;
|
|
||||||
Color *config_text;
|
|
||||||
int width = 0, height;
|
|
||||||
Panel *panel = (Panel *)task->area.panel;
|
|
||||||
// printf("draw_task %d %d\n", task->area.posx, task->area.posy);
|
|
||||||
|
|
||||||
|
int text_width = 0;
|
||||||
if (panel->g_task.text) {
|
if (panel->g_task.text) {
|
||||||
/* Layout */
|
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||||
layout = pango_cairo_create_layout(c);
|
|
||||||
pango_layout_set_font_description(layout, panel->g_task.font_desc);
|
pango_layout_set_font_description(layout, panel->g_task.font_desc);
|
||||||
pango_layout_set_text(layout, task->title, -1);
|
pango_layout_set_text(layout, task->title, -1);
|
||||||
|
|
||||||
/* Drawing width and Cut text */
|
|
||||||
// pango use U+22EF or U+2026
|
|
||||||
pango_layout_set_width(layout, ((Taskbar *)task->area.parent)->text_width * PANGO_SCALE);
|
pango_layout_set_width(layout, ((Taskbar *)task->area.parent)->text_width * PANGO_SCALE);
|
||||||
pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE);
|
pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE);
|
||||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||||
|
|
||||||
/* Center text */
|
|
||||||
if (panel->g_task.centered)
|
if (panel->g_task.centered)
|
||||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||||
else
|
else
|
||||||
pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
|
pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
|
||||||
|
|
||||||
pango_layout_get_pixel_size(layout, &width, &height);
|
int text_height;
|
||||||
|
pango_layout_get_pixel_size(layout, &text_width, &text_height);
|
||||||
config_text = &panel->g_task.font[task->current_state];
|
double text_posy = (panel->g_task.area.height - text_height) / 2.0;
|
||||||
|
|
||||||
double text_posy = (panel->g_task.area.height - height) / 2.0;
|
|
||||||
|
|
||||||
|
Color *config_text = &panel->g_task.font[task->current_state];
|
||||||
draw_text(layout, c, panel->g_task.text_posx, text_posy, config_text, panel->font_shadow);
|
draw_text(layout, c, panel->g_task.text_posx, text_posy, config_text, panel->font_shadow);
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel->g_task.icon) {
|
if (panel->g_task.icon) {
|
||||||
draw_task_icon(task, width);
|
draw_task_icon(task, text_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_change_task(void *obj)
|
void on_change_task(void *obj)
|
||||||
{
|
{
|
||||||
Task *task = obj;
|
Task *task = (Task *)obj;
|
||||||
Panel *panel = (Panel *)task->area.panel;
|
Panel *panel = (Panel *)task->area.panel;
|
||||||
|
|
||||||
long value[] = {panel->posx + task->area.posx, panel->posy + task->area.posy, task->area.width, task->area.height};
|
long value[] = {panel->posx + task->area.posx, panel->posy + task->area.posy, task->area.width, task->area.height};
|
||||||
@@ -467,21 +455,18 @@ void on_change_task(void *obj)
|
|||||||
set_task_redraw(task);
|
set_task_redraw(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a pointer to the active task (active_task) and a pointer
|
Task *find_active_task(Task *current_task)
|
||||||
// to the task that is currently under the mouse (current_task),
|
|
||||||
// returns a pointer to the active task.
|
|
||||||
Task *find_active_task(Task *current_task, Task *active_task)
|
|
||||||
{
|
{
|
||||||
if (active_task == NULL)
|
if (active_task == NULL)
|
||||||
return current_task;
|
return current_task;
|
||||||
|
|
||||||
Taskbar *taskbar = current_task->area.parent;
|
Taskbar *taskbar = (Taskbar *)current_task->area.parent;
|
||||||
|
|
||||||
GList *l0 = taskbar->area.children;
|
GList *l0 = taskbar->area.children;
|
||||||
if (taskbarname_enabled)
|
if (taskbarname_enabled)
|
||||||
l0 = l0->next;
|
l0 = l0->next;
|
||||||
for (; l0; l0 = l0->next) {
|
for (; l0; l0 = l0->next) {
|
||||||
Task *task = l0->data;
|
Task *task = (Task *)l0->data;
|
||||||
if (task->win == active_task->win)
|
if (task->win == active_task->win)
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
@@ -492,7 +477,7 @@ Task *find_active_task(Task *current_task, Task *active_task)
|
|||||||
Task *next_task(Task *task)
|
Task *next_task(Task *task)
|
||||||
{
|
{
|
||||||
if (!task)
|
if (!task)
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
Taskbar *taskbar = task->area.parent;
|
Taskbar *taskbar = task->area.parent;
|
||||||
|
|
||||||
@@ -508,7 +493,7 @@ Task *next_task(Task *task)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task *prev_task(Task *task)
|
Task *prev_task(Task *task)
|
||||||
@@ -535,14 +520,14 @@ Task *prev_task(Task *task)
|
|||||||
task2 = task1;
|
task2 = task1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void active_task()
|
void reset_active_task()
|
||||||
{
|
{
|
||||||
if (task_active) {
|
if (active_task) {
|
||||||
set_task_state(task_active, window_is_iconified(task_active->win) ? TASK_ICONIFIED : TASK_NORMAL);
|
set_task_state(active_task, window_is_iconified(active_task->win) ? TASK_ICONIFIED : TASK_NORMAL);
|
||||||
task_active = 0;
|
active_task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Window w1 = get_active_window();
|
Window w1 = get_active_window();
|
||||||
@@ -554,7 +539,7 @@ void active_task()
|
|||||||
while (XGetTransientForHint(server.dsp, w1, &w2))
|
while (XGetTransientForHint(server.dsp, w1, &w2))
|
||||||
w1 = w2;
|
w1 = w2;
|
||||||
}
|
}
|
||||||
set_task_state((task_active = task_get_task(w1)), TASK_ACTIVE);
|
set_task_state((active_task = task_get_task(w1)), TASK_ACTIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,8 +551,7 @@ void set_task_state(Task *task, TaskState state)
|
|||||||
if (task->current_state != state || hide_task_diff_monitor) {
|
if (task->current_state != state || hide_task_diff_monitor) {
|
||||||
GPtrArray *task_group = task_get_tasks(task->win);
|
GPtrArray *task_group = task_get_tasks(task->win);
|
||||||
if (task_group) {
|
if (task_group) {
|
||||||
int i;
|
for (int i = 0; i < task_group->len; ++i) {
|
||||||
for (i = 0; i < task_group->len; ++i) {
|
|
||||||
Task *task1 = g_ptr_array_index(task_group, i);
|
Task *task1 = g_ptr_array_index(task_group, i);
|
||||||
task1->current_state = state;
|
task1->current_state = state;
|
||||||
task1->area.bg = panels[0].g_task.background[state];
|
task1->area.bg = panels[0].g_task.background[state];
|
||||||
@@ -580,29 +564,29 @@ void set_task_state(Task *task, TaskState state)
|
|||||||
}
|
}
|
||||||
if (state == TASK_ACTIVE && g_slist_find(urgent_list, task1))
|
if (state == TASK_ACTIVE && g_slist_find(urgent_list, task1))
|
||||||
del_urgent(task1);
|
del_urgent(task1);
|
||||||
int hide = 0;
|
gboolean hide = FALSE;
|
||||||
Taskbar *taskbar = (Taskbar *)task1->area.parent;
|
Taskbar *taskbar = (Taskbar *)task1->area.parent;
|
||||||
if (task->desktop == ALLDESKTOP && server.desktop != taskbar->desktop) {
|
if (task->desktop == ALL_DESKTOPS && server.desktop != taskbar->desktop) {
|
||||||
// Hide ALLDESKTOP task on non-current desktop
|
// Hide ALL_DESKTOPS task on non-current desktop
|
||||||
hide = 1;
|
hide = TRUE;
|
||||||
}
|
}
|
||||||
if (hide_inactive_tasks) {
|
if (hide_inactive_tasks) {
|
||||||
// Show only the active task
|
// Show only the active task
|
||||||
if (state != TASK_ACTIVE) {
|
if (state != TASK_ACTIVE) {
|
||||||
hide = 1;
|
hide = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor &&
|
if (get_window_monitor(task->win) != ((Panel *)task->area.panel)->monitor &&
|
||||||
(hide_task_diff_monitor || num_panels > 1)) {
|
(hide_task_diff_monitor || num_panels > 1)) {
|
||||||
hide = 1;
|
hide = TRUE;
|
||||||
}
|
}
|
||||||
if (1 - hide != task1->area.on_screen) {
|
if ((!hide) != task1->area.on_screen) {
|
||||||
task1->area.on_screen = TRUE - hide;
|
task1->area.on_screen = !hide;
|
||||||
set_task_redraw(task1);
|
set_task_redraw(task1);
|
||||||
Panel *p = (Panel *)task->area.panel;
|
Panel *p = (Panel *)task->area.panel;
|
||||||
task->area.resize_needed = 1;
|
task->area.resize_needed = TRUE;
|
||||||
p->taskbar->area.resize_needed = 1;
|
p->taskbar->area.resize_needed = TRUE;
|
||||||
p->area.resize_needed = 1;
|
p->area.resize_needed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panel_refresh = TRUE;
|
panel_refresh = TRUE;
|
||||||
@@ -612,8 +596,7 @@ void set_task_state(Task *task, TaskState state)
|
|||||||
|
|
||||||
void set_task_redraw(Task *task)
|
void set_task_redraw(Task *task)
|
||||||
{
|
{
|
||||||
int k;
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
for (k = 0; k < TASK_STATE_COUNT; ++k) {
|
|
||||||
if (task->state_pix[k])
|
if (task->state_pix[k])
|
||||||
XFreePixmap(server.dsp, task->state_pix[k]);
|
XFreePixmap(server.dsp, task->state_pix[k]);
|
||||||
task->state_pix[k] = 0;
|
task->state_pix[k] = 0;
|
||||||
@@ -644,7 +627,7 @@ void add_urgent(Task *task)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// some programs set urgency hint although they are active
|
// some programs set urgency hint although they are active
|
||||||
if (task_active && task_active->win == task->win)
|
if (active_task && active_task->win == task->win)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
task = task_get_task(task->win); // always add the first task for a task group (omnipresent windows)
|
task = task_get_task(task->win); // always add the first task for a task group (omnipresent windows)
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ typedef enum TaskState {
|
|||||||
extern timeout *urgent_timeout;
|
extern timeout *urgent_timeout;
|
||||||
extern GSList *urgent_list;
|
extern GSList *urgent_list;
|
||||||
|
|
||||||
// --------------------------------------------------
|
|
||||||
// global task parameter
|
|
||||||
typedef struct GlobalTask {
|
typedef struct GlobalTask {
|
||||||
Area area;
|
Area area;
|
||||||
|
|
||||||
@@ -52,7 +50,10 @@ typedef struct GlobalTask {
|
|||||||
gboolean tooltip_enabled;
|
gboolean tooltip_enabled;
|
||||||
} GlobalTask;
|
} GlobalTask;
|
||||||
|
|
||||||
typedef struct {
|
// Stores information about a task.
|
||||||
|
// Warning: any dynamically allocated members are shared between the Task instances created for the same window
|
||||||
|
// (for example, if the task appears on all desktops, there will be a different instance on each desktop's taskbar).
|
||||||
|
typedef struct Task {
|
||||||
// always start with area
|
// always start with area
|
||||||
Area area;
|
Area area;
|
||||||
|
|
||||||
@@ -83,11 +84,15 @@ void on_change_task(void *obj);
|
|||||||
|
|
||||||
void get_icon(Task *task);
|
void get_icon(Task *task);
|
||||||
gboolean get_title(Task *task);
|
gboolean get_title(Task *task);
|
||||||
void active_task();
|
void reset_active_task();
|
||||||
void set_task_state(Task *task, TaskState state);
|
void set_task_state(Task *task, TaskState state);
|
||||||
void set_task_redraw(Task *task);
|
void set_task_redraw(Task *task);
|
||||||
|
|
||||||
Task *find_active_task(Task *current_task, Task *active_task);
|
// Given a pointer to the task that is currently under the mouse (current_task),
|
||||||
|
// returns a pointer to the Task for the active window on the same taskbar.
|
||||||
|
// If not found, returns the current task.
|
||||||
|
Task *find_active_task(Task *current_task);
|
||||||
|
|
||||||
Task *next_task(Task *task);
|
Task *next_task(Task *task);
|
||||||
Task *prev_task(Task *task);
|
Task *prev_task(Task *task);
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,13 @@
|
|||||||
#include "panel.h"
|
#include "panel.h"
|
||||||
#include "strnatcmp.h"
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
/* win_to_task_table holds for every Window an array of tasks. Usually the array contains only one
|
/* win_to_task holds for every Window an array of tasks. Usually the array contains only one
|
||||||
element. However for omnipresent windows (windows which are visible in every taskbar) the array
|
element. However for omnipresent windows (windows which are visible in every taskbar) the array
|
||||||
contains to every Task* on each panel a pointer (i.e. GPtrArray.len == server.num_desktops)
|
contains to every Task* on each panel a pointer (i.e. GPtrArray.len == server.num_desktops)
|
||||||
*/
|
*/
|
||||||
GHashTable *win_to_task_table;
|
GHashTable *win_to_task;
|
||||||
|
|
||||||
Task *task_active;
|
Task *active_task;
|
||||||
Task *task_drag;
|
Task *task_drag;
|
||||||
gboolean taskbar_enabled;
|
gboolean taskbar_enabled;
|
||||||
gboolean taskbar_distribute_size;
|
gboolean taskbar_distribute_size;
|
||||||
@@ -50,12 +50,14 @@ Alignment taskbar_alignment;
|
|||||||
|
|
||||||
guint win_hash(gconstpointer key)
|
guint win_hash(gconstpointer key)
|
||||||
{
|
{
|
||||||
return (guint) * ((const Window *)key);
|
return *((const Window *)key);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean win_compare(gconstpointer a, gconstpointer b)
|
gboolean win_compare(gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
return (*((const Window *)a) == *((const Window *)b));
|
return (*((const Window *)a) == *((const Window *)b));
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_ptr_array(gpointer data)
|
void free_ptr_array(gpointer data)
|
||||||
{
|
{
|
||||||
g_ptr_array_free(data, 1);
|
g_ptr_array_free(data, 1);
|
||||||
@@ -63,7 +65,7 @@ void free_ptr_array(gpointer data)
|
|||||||
|
|
||||||
void default_taskbar()
|
void default_taskbar()
|
||||||
{
|
{
|
||||||
win_to_task_table = NULL;
|
win_to_task = NULL;
|
||||||
urgent_timeout = NULL;
|
urgent_timeout = NULL;
|
||||||
urgent_list = NULL;
|
urgent_list = NULL;
|
||||||
taskbar_enabled = 0;
|
taskbar_enabled = 0;
|
||||||
@@ -77,29 +79,25 @@ void default_taskbar()
|
|||||||
|
|
||||||
void cleanup_taskbar()
|
void cleanup_taskbar()
|
||||||
{
|
{
|
||||||
Panel *panel;
|
|
||||||
Taskbar *taskbar;
|
|
||||||
int i, j, k;
|
|
||||||
|
|
||||||
cleanup_taskbarname();
|
cleanup_taskbarname();
|
||||||
if (win_to_task_table) {
|
if (win_to_task) {
|
||||||
while (g_hash_table_size(win_to_task_table)) {
|
while (g_hash_table_size(win_to_task)) {
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
gpointer key, value;
|
gpointer key, value;
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, win_to_task_table);
|
g_hash_table_iter_init(&iter, win_to_task);
|
||||||
if (g_hash_table_iter_next(&iter, &key, &value)) {
|
if (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||||
taskbar_remove_task(key, 0, 0);
|
taskbar_remove_task(key, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_hash_table_destroy(win_to_task_table);
|
g_hash_table_destroy(win_to_task);
|
||||||
win_to_task_table = NULL;
|
win_to_task = NULL;
|
||||||
}
|
}
|
||||||
for (i = 0; i < num_panels; i++) {
|
for (int i = 0; i < num_panels; i++) {
|
||||||
panel = &panels[i];
|
Panel *panel = &panels[i];
|
||||||
for (j = 0; j < panel->num_desktops; j++) {
|
for (int j = 0; j < panel->num_desktops; j++) {
|
||||||
taskbar = &panel->taskbar[j];
|
Taskbar *taskbar = &panel->taskbar[j];
|
||||||
for (k = 0; k < TASKBAR_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASKBAR_STATE_COUNT; ++k) {
|
||||||
if (taskbar->state_pix[k])
|
if (taskbar->state_pix[k])
|
||||||
XFreePixmap(server.dsp, taskbar->state_pix[k]);
|
XFreePixmap(server.dsp, taskbar->state_pix[k]);
|
||||||
taskbar->state_pix[k] = 0;
|
taskbar->state_pix[k] = 0;
|
||||||
@@ -122,17 +120,16 @@ void cleanup_taskbar()
|
|||||||
|
|
||||||
void init_taskbar()
|
void init_taskbar()
|
||||||
{
|
{
|
||||||
if (!win_to_task_table)
|
if (!win_to_task)
|
||||||
win_to_task_table = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
|
win_to_task = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
|
||||||
|
|
||||||
task_active = 0;
|
active_task = 0;
|
||||||
task_drag = 0;
|
task_drag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_taskbar_panel(void *p)
|
void init_taskbar_panel(void *p)
|
||||||
{
|
{
|
||||||
Panel *panel = (Panel *)p;
|
Panel *panel = (Panel *)p;
|
||||||
int j;
|
|
||||||
|
|
||||||
if (!panel->g_taskbar.background[TASKBAR_NORMAL]) {
|
if (!panel->g_taskbar.background[TASKBAR_NORMAL]) {
|
||||||
panel->g_taskbar.background[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, 0);
|
panel->g_taskbar.background[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, 0);
|
||||||
@@ -235,7 +232,7 @@ void init_taskbar_panel(void *p)
|
|||||||
panel->g_task.area.height = panel->g_task.maximum_height;
|
panel->g_task.area.height = panel->g_task.maximum_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < TASK_STATE_COUNT; ++j) {
|
for (int j = 0; j < TASK_STATE_COUNT; ++j) {
|
||||||
if (!panel->g_task.background[j])
|
if (!panel->g_task.background[j])
|
||||||
panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0);
|
panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0);
|
||||||
if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) {
|
if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) {
|
||||||
@@ -275,7 +272,7 @@ void init_taskbar_panel(void *p)
|
|||||||
Taskbar *taskbar;
|
Taskbar *taskbar;
|
||||||
panel->num_desktops = server.num_desktops;
|
panel->num_desktops = server.num_desktops;
|
||||||
panel->taskbar = calloc(server.num_desktops, sizeof(Taskbar));
|
panel->taskbar = calloc(server.num_desktops, sizeof(Taskbar));
|
||||||
for (j = 0; j < panel->num_desktops; j++) {
|
for (int j = 0; j < panel->num_desktops; j++) {
|
||||||
taskbar = &panel->taskbar[j];
|
taskbar = &panel->taskbar[j];
|
||||||
memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area));
|
memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area));
|
||||||
taskbar->desktop = j;
|
taskbar->desktop = j;
|
||||||
@@ -297,32 +294,30 @@ Task *task_get_task(Window win)
|
|||||||
GPtrArray *task_group = task_get_tasks(win);
|
GPtrArray *task_group = task_get_tasks(win);
|
||||||
if (task_group)
|
if (task_group)
|
||||||
return g_ptr_array_index(task_group, 0);
|
return g_ptr_array_index(task_group, 0);
|
||||||
else
|
return NULL;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPtrArray *task_get_tasks(Window win)
|
GPtrArray *task_get_tasks(Window win)
|
||||||
{
|
{
|
||||||
if (win_to_task_table && taskbar_enabled)
|
if (win_to_task && taskbar_enabled)
|
||||||
return g_hash_table_lookup(win_to_task_table, &win);
|
return g_hash_table_lookup(win_to_task, &win);
|
||||||
else
|
return NULL;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_refresh_tasklist()
|
void task_refresh_tasklist()
|
||||||
{
|
{
|
||||||
Window *win;
|
|
||||||
int num_results, i;
|
|
||||||
|
|
||||||
if (!taskbar_enabled)
|
if (!taskbar_enabled)
|
||||||
return;
|
return;
|
||||||
win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
|
||||||
|
int num_results;
|
||||||
|
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
||||||
if (!win)
|
if (!win)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GList *win_list = g_hash_table_get_keys(win_to_task_table);
|
GList *win_list = g_hash_table_get_keys(win_to_task);
|
||||||
GList *it;
|
GList *it;
|
||||||
for (it = win_list; it; it = it->next) {
|
for (it = win_list; it; it = it->next) {
|
||||||
|
int i;
|
||||||
for (i = 0; i < num_results; i++)
|
for (i = 0; i < num_results; i++)
|
||||||
if (*((Window *)it->data) == win[i])
|
if (*((Window *)it->data) == win[i])
|
||||||
break;
|
break;
|
||||||
@@ -332,7 +327,7 @@ void task_refresh_tasklist()
|
|||||||
g_list_free(win_list);
|
g_list_free(win_list);
|
||||||
|
|
||||||
// Add any new
|
// Add any new
|
||||||
for (i = 0; i < num_results; i++)
|
for (int i = 0; i < num_results; i++)
|
||||||
if (!task_get_task(win[i]))
|
if (!task_get_task(win[i]))
|
||||||
add_task(win[i]);
|
add_task(win[i]);
|
||||||
|
|
||||||
@@ -351,13 +346,12 @@ gboolean resize_taskbar(void *obj)
|
|||||||
{
|
{
|
||||||
Taskbar *taskbar = (Taskbar *)obj;
|
Taskbar *taskbar = (Taskbar *)obj;
|
||||||
Panel *panel = (Panel *)taskbar->area.panel;
|
Panel *panel = (Panel *)taskbar->area.panel;
|
||||||
int text_width;
|
|
||||||
|
|
||||||
// printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
|
// printf("resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
|
||||||
if (panel_horizontal) {
|
if (panel_horizontal) {
|
||||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
|
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
|
||||||
|
|
||||||
text_width = panel->g_task.maximum_width;
|
int text_width = panel->g_task.maximum_width;
|
||||||
GList *l = taskbar->area.children;
|
GList *l = taskbar->area.children;
|
||||||
if (taskbarname_enabled)
|
if (taskbarname_enabled)
|
||||||
l = l->next;
|
l = l->next;
|
||||||
@@ -368,23 +362,22 @@ gboolean resize_taskbar(void *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
taskbar->text_width =
|
taskbar->text_width =
|
||||||
text_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
|
text_width - panel->g_task.text_posx - panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
|
||||||
} else {
|
} else {
|
||||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height);
|
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height);
|
||||||
|
|
||||||
taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx -
|
taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx -
|
||||||
panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
|
panel->g_task.area.bg->border.width - panel->g_task.area.paddingxlr;
|
||||||
}
|
}
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_change_taskbar(void *obj)
|
void on_change_taskbar(void *obj)
|
||||||
{
|
{
|
||||||
Taskbar *taskbar = (Taskbar *)obj;
|
Taskbar *taskbar = (Taskbar *)obj;
|
||||||
int k;
|
|
||||||
|
|
||||||
// reset Pixmap when position/size changed
|
// reset Pixmap when position/size changed
|
||||||
for (k = 0; k < TASKBAR_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASKBAR_STATE_COUNT; ++k) {
|
||||||
if (taskbar->state_pix[k])
|
if (taskbar->state_pix[k])
|
||||||
XFreePixmap(server.dsp, taskbar->state_pix[k]);
|
XFreePixmap(server.dsp, taskbar->state_pix[k]);
|
||||||
taskbar->state_pix[k] = 0;
|
taskbar->state_pix[k] = 0;
|
||||||
@@ -426,7 +419,7 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state)
|
|||||||
if (taskbarname_enabled)
|
if (taskbarname_enabled)
|
||||||
l = l->next;
|
l = l->next;
|
||||||
for (; l; l = l->next)
|
for (; l; l = l->next)
|
||||||
set_task_redraw(l->data);
|
set_task_redraw((Task *)l->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panel_refresh = TRUE;
|
panel_refresh = TRUE;
|
||||||
@@ -435,10 +428,9 @@ void set_taskbar_state(Taskbar *taskbar, TaskbarState state)
|
|||||||
void visible_taskbar(void *p)
|
void visible_taskbar(void *p)
|
||||||
{
|
{
|
||||||
Panel *panel = (Panel *)p;
|
Panel *panel = (Panel *)p;
|
||||||
int j;
|
|
||||||
|
|
||||||
Taskbar *taskbar;
|
Taskbar *taskbar;
|
||||||
for (j = 0; j < panel->num_desktops; j++) {
|
for (int j = 0; j < panel->num_desktops; j++) {
|
||||||
taskbar = &panel->taskbar[j];
|
taskbar = &panel->taskbar[j];
|
||||||
if (taskbar_mode != MULTI_DESKTOP && taskbar->desktop != server.desktop) {
|
if (taskbar_mode != MULTI_DESKTOP && taskbar->desktop != server.desktop) {
|
||||||
// SINGLE_DESKTOP and not current desktop
|
// SINGLE_DESKTOP and not current desktop
|
||||||
@@ -493,11 +485,10 @@ gint compare_task_centers(Task *a, Task *b, Taskbar *taskbar)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// Compare centers
|
// Compare centers
|
||||||
int a_horiz_c, a_vert_c, b_horiz_c, b_vert_c;
|
int a_horiz_c = a->win_x + a->win_w / 2;
|
||||||
a_horiz_c = a->win_x + a->win_w / 2;
|
int b_horiz_c = b->win_x + b->win_w / 2;
|
||||||
b_horiz_c = b->win_x + b->win_w / 2;
|
int a_vert_c = a->win_y + a->win_h / 2;
|
||||||
a_vert_c = a->win_y + a->win_h / 2;
|
int b_vert_c = b->win_y + b->win_h / 2;
|
||||||
b_vert_c = b->win_y + b->win_h / 2;
|
|
||||||
if (panel_horizontal) {
|
if (panel_horizontal) {
|
||||||
if (a_horiz_c != b_horiz_c) {
|
if (a_horiz_c != b_horiz_c) {
|
||||||
return a_horiz_c - b_horiz_c;
|
return a_horiz_c - b_horiz_c;
|
||||||
@@ -534,19 +525,18 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int taskbar_needs_sort(Taskbar *taskbar)
|
gboolean taskbar_needs_sort(Taskbar *taskbar)
|
||||||
{
|
{
|
||||||
if (taskbar_sort_method == TASKBAR_NOSORT)
|
if (taskbar_sort_method == TASKBAR_NOSORT)
|
||||||
return 0;
|
return FALSE;
|
||||||
|
|
||||||
GList *i, *j;
|
for (GList *i = taskbar->area.children, *j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
|
||||||
for (i = taskbar->area.children, j = i ? i->next : NULL; i && j; i = i->next, j = j->next) {
|
|
||||||
if (compare_tasks(i->data, j->data, taskbar) > 0) {
|
if (compare_tasks(i->data, j->data, taskbar) > 0) {
|
||||||
return 1;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sort_tasks(Taskbar *taskbar)
|
void sort_tasks(Taskbar *taskbar)
|
||||||
@@ -557,9 +547,9 @@ void sort_tasks(Taskbar *taskbar)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
taskbar->area.children = g_list_sort_with_data(taskbar->area.children, (GCompareDataFunc)compare_tasks, taskbar);
|
taskbar->area.children = g_list_sort_with_data(taskbar->area.children, (GCompareDataFunc)compare_tasks, taskbar);
|
||||||
taskbar->area.resize_needed = 1;
|
taskbar->area.resize_needed = TRUE;
|
||||||
panel_refresh = TRUE;
|
panel_refresh = TRUE;
|
||||||
((Panel *)taskbar->area.panel)->area.resize_needed = 1;
|
((Panel *)taskbar->area.panel)->area.resize_needed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sort_taskbar_for_win(Window win)
|
void sort_taskbar_for_win(Window win)
|
||||||
@@ -569,12 +559,11 @@ void sort_taskbar_for_win(Window win)
|
|||||||
|
|
||||||
GPtrArray *task_group = task_get_tasks(win);
|
GPtrArray *task_group = task_get_tasks(win);
|
||||||
if (task_group) {
|
if (task_group) {
|
||||||
int i;
|
|
||||||
Task *task0 = g_ptr_array_index(task_group, 0);
|
Task *task0 = g_ptr_array_index(task_group, 0);
|
||||||
if (task0) {
|
if (task0) {
|
||||||
get_window_coordinates(win, &task0->win_x, &task0->win_y, &task0->win_w, &task0->win_h);
|
get_window_coordinates(win, &task0->win_x, &task0->win_y, &task0->win_w, &task0->win_h);
|
||||||
}
|
}
|
||||||
for (i = 0; i < task_group->len; ++i) {
|
for (int i = 0; i < task_group->len; ++i) {
|
||||||
Task *task = g_ptr_array_index(task_group, i);
|
Task *task = g_ptr_array_index(task_group, i);
|
||||||
task->win_x = task0->win_x;
|
task->win_x = task0->win_x;
|
||||||
task->win_y = task0->win_y;
|
task->win_y = task0->win_y;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ typedef enum TaskbarSortMethod {
|
|||||||
TASKBAR_SORT_TITLE,
|
TASKBAR_SORT_TITLE,
|
||||||
} TaskbarSortMethod;
|
} TaskbarSortMethod;
|
||||||
|
|
||||||
extern GHashTable *win_to_task_table;
|
extern GHashTable *win_to_task;
|
||||||
extern Task *task_active;
|
extern Task *active_task;
|
||||||
extern Task *task_drag;
|
extern Task *task_drag;
|
||||||
extern gboolean taskbar_enabled;
|
extern gboolean taskbar_enabled;
|
||||||
extern gboolean taskbar_distribute_size;
|
extern gboolean taskbar_distribute_size;
|
||||||
|
|||||||
241
src/tint.c
241
src/tint.c
@@ -113,7 +113,7 @@ void init(int argc, char *argv[])
|
|||||||
default_config();
|
default_config();
|
||||||
default_timeout();
|
default_timeout();
|
||||||
default_systray();
|
default_systray();
|
||||||
memset(&server, 0, sizeof(Server_global));
|
memset(&server, 0, sizeof(server));
|
||||||
#ifdef ENABLE_BATTERY
|
#ifdef ENABLE_BATTERY
|
||||||
default_battery();
|
default_battery();
|
||||||
#endif
|
#endif
|
||||||
@@ -390,7 +390,7 @@ void window_action(Task *task, int action)
|
|||||||
XIconifyWindow(server.dsp, task->win, server.screen);
|
XIconifyWindow(server.dsp, task->win, server.screen);
|
||||||
break;
|
break;
|
||||||
case TOGGLE_ICONIFY:
|
case TOGGLE_ICONIFY:
|
||||||
if (task_active && task->win == task_active->win)
|
if (active_task && task->win == active_task->win)
|
||||||
XIconifyWindow(server.dsp, task->win, server.screen);
|
XIconifyWindow(server.dsp, task->win, server.screen);
|
||||||
else
|
else
|
||||||
activate_window(task->win);
|
activate_window(task->win);
|
||||||
@@ -425,12 +425,12 @@ void window_action(Task *task, int action)
|
|||||||
break;
|
break;
|
||||||
case NEXT_TASK: {
|
case NEXT_TASK: {
|
||||||
Task *task1;
|
Task *task1;
|
||||||
task1 = next_task(find_active_task(task, task_active));
|
task1 = next_task(find_active_task(task));
|
||||||
activate_window(task1->win);
|
activate_window(task1->win);
|
||||||
} break;
|
} break;
|
||||||
case PREV_TASK: {
|
case PREV_TASK: {
|
||||||
Task *task1;
|
Task *task1;
|
||||||
task1 = prev_task(find_active_task(task, task_active));
|
task1 = prev_task(find_active_task(task));
|
||||||
activate_window(task1->win);
|
activate_window(task1->win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,7 +544,7 @@ void event_button_motion_notify(XEvent *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // The event is on another taskbar than the task being dragged
|
} else { // The event is on another taskbar than the task being dragged
|
||||||
if (task_drag->desktop == ALLDESKTOP || taskbar_mode != MULTI_DESKTOP)
|
if (task_drag->desktop == ALL_DESKTOPS || taskbar_mode != MULTI_DESKTOP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent;
|
Taskbar *drag_taskbar = (Taskbar *)task_drag->area.parent;
|
||||||
@@ -658,18 +658,74 @@ void event_button_release(XEvent *e)
|
|||||||
|
|
||||||
// switch desktop
|
// switch desktop
|
||||||
if (taskbar_mode == MULTI_DESKTOP) {
|
if (taskbar_mode == MULTI_DESKTOP) {
|
||||||
if (taskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT && action != DESKTOP_RIGHT)
|
gboolean diff_desktop = FALSE;
|
||||||
|
if (taskbar->desktop != server.desktop && action != CLOSE && action != DESKTOP_LEFT && action != DESKTOP_RIGHT) {
|
||||||
|
diff_desktop = TRUE;
|
||||||
change_desktop(taskbar->desktop);
|
change_desktop(taskbar->desktop);
|
||||||
|
}
|
||||||
|
Task *task = click_task(panel, e->xbutton.x, e->xbutton.y);
|
||||||
|
if (task) {
|
||||||
|
if (diff_desktop) {
|
||||||
|
if (action == TOGGLE_ICONIFY) {
|
||||||
|
if (!window_is_active(task->win))
|
||||||
|
activate_window(task->win);
|
||||||
|
} else {
|
||||||
|
window_action(task, action);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window_action(task, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window_action(click_task(panel, e->xbutton.x, e->xbutton.y), action);
|
||||||
}
|
}
|
||||||
|
|
||||||
// action on task
|
|
||||||
window_action(click_task(panel, e->xbutton.x, e->xbutton.y), action);
|
|
||||||
|
|
||||||
// to keep window below
|
// to keep window below
|
||||||
if (panel_layer == BOTTOM_LAYER)
|
if (panel_layer == BOTTOM_LAYER)
|
||||||
XLowerWindow(server.dsp, panel->main_win);
|
XLowerWindow(server.dsp, panel->main_win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_desktop_names()
|
||||||
|
{
|
||||||
|
if (!taskbarname_enabled)
|
||||||
|
return;
|
||||||
|
GSList *list = get_desktop_names();
|
||||||
|
for (int i = 0; i < num_panels; i++) {
|
||||||
|
int j;
|
||||||
|
GSList *l;
|
||||||
|
for (j = 0, l = list; j < panels[i].num_desktops; j++) {
|
||||||
|
gchar *name;
|
||||||
|
if (l) {
|
||||||
|
name = g_strdup(l->data);
|
||||||
|
l = l->next;
|
||||||
|
} else {
|
||||||
|
name = g_strdup_printf("%d", j + 1);
|
||||||
|
}
|
||||||
|
Taskbar *taskbar = &panels[i].taskbar[j];
|
||||||
|
if (strcmp(name, taskbar->bar_name.name) != 0) {
|
||||||
|
g_free(taskbar->bar_name.name);
|
||||||
|
taskbar->bar_name.name = name;
|
||||||
|
taskbar->bar_name.area.resize_needed = 1;
|
||||||
|
} else {
|
||||||
|
g_free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (GSList *l = list; l; l = l->next)
|
||||||
|
g_free(l->data);
|
||||||
|
g_slist_free(list);
|
||||||
|
panel_refresh = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_task_desktop(Task *task)
|
||||||
|
{
|
||||||
|
Window win = task->win;
|
||||||
|
remove_task(task);
|
||||||
|
task = add_task(win);
|
||||||
|
reset_active_task();
|
||||||
|
panel_refresh = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void event_property_notify(XEvent *e)
|
void event_property_notify(XEvent *e)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -686,93 +742,93 @@ void event_property_notify(XEvent *e)
|
|||||||
|
|
||||||
// Change name of desktops
|
// Change name of desktops
|
||||||
else if (at == server.atom._NET_DESKTOP_NAMES) {
|
else if (at == server.atom._NET_DESKTOP_NAMES) {
|
||||||
if (!taskbarname_enabled)
|
update_desktop_names();
|
||||||
return;
|
|
||||||
GSList *l, *list = get_desktop_names();
|
|
||||||
int j;
|
|
||||||
gchar *name;
|
|
||||||
Taskbar *taskbar;
|
|
||||||
for (i = 0; i < num_panels; i++) {
|
|
||||||
for (j = 0, l = list; j < panels[i].num_desktops; j++) {
|
|
||||||
if (l) {
|
|
||||||
name = g_strdup(l->data);
|
|
||||||
l = l->next;
|
|
||||||
} else
|
|
||||||
name = g_strdup_printf("%d", j + 1);
|
|
||||||
taskbar = &panels[i].taskbar[j];
|
|
||||||
if (strcmp(name, taskbar->bar_name.name) != 0) {
|
|
||||||
g_free(taskbar->bar_name.name);
|
|
||||||
taskbar->bar_name.name = name;
|
|
||||||
taskbar->bar_name.area.resize_needed = 1;
|
|
||||||
} else
|
|
||||||
g_free(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (l = list; l; l = l->next)
|
|
||||||
g_free(l->data);
|
|
||||||
g_slist_free(list);
|
|
||||||
panel_refresh = TRUE;
|
|
||||||
}
|
}
|
||||||
// Change number of desktops
|
// Change desktops
|
||||||
else if (at == server.atom._NET_NUMBER_OF_DESKTOPS) {
|
else if (at == server.atom._NET_NUMBER_OF_DESKTOPS ||
|
||||||
if (!taskbar_enabled)
|
at == server.atom._NET_DESKTOP_GEOMETRY ||
|
||||||
return;
|
at == server.atom._NET_DESKTOP_VIEWPORT ||
|
||||||
server.num_desktops = server_get_number_of_desktops();
|
at == server.atom._NET_WORKAREA ||
|
||||||
if (server.num_desktops <= server.desktop) {
|
at == server.atom._NET_CURRENT_DESKTOP) {
|
||||||
server.desktop = server.num_desktops - 1;
|
|
||||||
}
|
|
||||||
cleanup_taskbar();
|
|
||||||
init_taskbar();
|
|
||||||
for (i = 0; i < num_panels; i++) {
|
|
||||||
init_taskbar_panel(&panels[i]);
|
|
||||||
set_panel_items_order(&panels[i]);
|
|
||||||
visible_taskbar(&panels[i]);
|
|
||||||
panels[i].area.resize_needed = 1;
|
|
||||||
}
|
|
||||||
task_refresh_tasklist();
|
|
||||||
active_task();
|
|
||||||
panel_refresh = TRUE;
|
|
||||||
}
|
|
||||||
// Change desktop
|
|
||||||
else if (at == server.atom._NET_CURRENT_DESKTOP) {
|
|
||||||
if (!taskbar_enabled)
|
if (!taskbar_enabled)
|
||||||
return;
|
return;
|
||||||
|
int old_num_desktops = server.num_desktops;
|
||||||
int old_desktop = server.desktop;
|
int old_desktop = server.desktop;
|
||||||
|
server_get_number_of_desktops();
|
||||||
server.desktop = get_current_desktop();
|
server.desktop = get_current_desktop();
|
||||||
for (i = 0; i < num_panels; i++) {
|
if (old_num_desktops != server.num_desktops) {
|
||||||
Panel *panel = &panels[i];
|
if (server.num_desktops <= server.desktop) {
|
||||||
set_taskbar_state(&panel->taskbar[old_desktop], TASKBAR_NORMAL);
|
server.desktop = server.num_desktops - 1;
|
||||||
set_taskbar_state(&panel->taskbar[server.desktop], TASKBAR_ACTIVE);
|
}
|
||||||
// check ALLDESKTOP task => resize taskbar
|
cleanup_taskbar();
|
||||||
Taskbar *taskbar;
|
init_taskbar();
|
||||||
Task *task;
|
for (i = 0; i < num_panels; i++) {
|
||||||
if (server.num_desktops > old_desktop) {
|
init_taskbar_panel(&panels[i]);
|
||||||
taskbar = &panel->taskbar[old_desktop];
|
set_panel_items_order(&panels[i]);
|
||||||
|
visible_taskbar(&panels[i]);
|
||||||
|
panels[i].area.resize_needed = 1;
|
||||||
|
}
|
||||||
|
task_refresh_tasklist();
|
||||||
|
reset_active_task();
|
||||||
|
panel_refresh = TRUE;
|
||||||
|
} else if (old_desktop != server.desktop) {
|
||||||
|
for (i = 0; i < num_panels; i++) {
|
||||||
|
Panel *panel = &panels[i];
|
||||||
|
set_taskbar_state(&panel->taskbar[old_desktop], TASKBAR_NORMAL);
|
||||||
|
set_taskbar_state(&panel->taskbar[server.desktop], TASKBAR_ACTIVE);
|
||||||
|
// check ALL_DESKTOPS task => resize taskbar
|
||||||
|
Taskbar *taskbar;
|
||||||
|
if (server.num_desktops > old_desktop) {
|
||||||
|
taskbar = &panel->taskbar[old_desktop];
|
||||||
|
GList *l = taskbar->area.children;
|
||||||
|
if (taskbarname_enabled)
|
||||||
|
l = l->next;
|
||||||
|
for (; l; l = l->next) {
|
||||||
|
Task *task = l->data;
|
||||||
|
if (task->desktop == ALL_DESKTOPS) {
|
||||||
|
task->area.on_screen = FALSE;
|
||||||
|
taskbar->area.resize_needed = 1;
|
||||||
|
panel_refresh = TRUE;
|
||||||
|
if (taskbar_mode == MULTI_DESKTOP)
|
||||||
|
panel->area.resize_needed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskbar = &panel->taskbar[server.desktop];
|
||||||
GList *l = taskbar->area.children;
|
GList *l = taskbar->area.children;
|
||||||
if (taskbarname_enabled)
|
if (taskbarname_enabled)
|
||||||
l = l->next;
|
l = l->next;
|
||||||
for (; l; l = l->next) {
|
for (; l; l = l->next) {
|
||||||
task = l->data;
|
Task *task = l->data;
|
||||||
if (task->desktop == ALLDESKTOP) {
|
if (task->desktop == ALL_DESKTOPS) {
|
||||||
task->area.on_screen = FALSE;
|
task->area.on_screen = TRUE;
|
||||||
taskbar->area.resize_needed = 1;
|
taskbar->area.resize_needed = 1;
|
||||||
panel_refresh = TRUE;
|
|
||||||
if (taskbar_mode == MULTI_DESKTOP)
|
if (taskbar_mode == MULTI_DESKTOP)
|
||||||
panel->area.resize_needed = 1;
|
panel->area.resize_needed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
taskbar = &panel->taskbar[server.desktop];
|
if (server.viewports) {
|
||||||
GList *l = taskbar->area.children;
|
GList *need_update = NULL;
|
||||||
if (taskbarname_enabled)
|
|
||||||
l = l->next;
|
GHashTableIter iter;
|
||||||
for (; l; l = l->next) {
|
gpointer key, value;
|
||||||
task = l->data;
|
|
||||||
if (task->desktop == ALLDESKTOP) {
|
g_hash_table_iter_init(&iter, win_to_task);
|
||||||
task->area.on_screen = TRUE;
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||||
taskbar->area.resize_needed = 1;
|
Window task_win = *(Window *)key;
|
||||||
if (taskbar_mode == MULTI_DESKTOP)
|
Task *task = task_get_task(task_win);
|
||||||
panel->area.resize_needed = 1;
|
if (task) {
|
||||||
|
int desktop = get_window_desktop(task_win);
|
||||||
|
if (desktop != task->desktop) {
|
||||||
|
need_update = g_list_append(need_update, task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (l = need_update; l; l = l->next) {
|
||||||
|
Task *task = l->data;
|
||||||
|
update_task_desktop(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -784,7 +840,7 @@ void event_property_notify(XEvent *e)
|
|||||||
}
|
}
|
||||||
// Change active
|
// Change active
|
||||||
else if (at == server.atom._NET_ACTIVE_WINDOW) {
|
else if (at == server.atom._NET_ACTIVE_WINDOW) {
|
||||||
active_task();
|
reset_active_task();
|
||||||
panel_refresh = TRUE;
|
panel_refresh = TRUE;
|
||||||
} else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) {
|
} else if (at == server.atom._XROOTPMAP_ID || at == server.atom._XROOTMAP_ID) {
|
||||||
// change Wallpaper
|
// change Wallpaper
|
||||||
@@ -838,7 +894,7 @@ void event_property_notify(XEvent *e)
|
|||||||
}
|
}
|
||||||
} else if (at == server.atom.WM_STATE) {
|
} else if (at == server.atom.WM_STATE) {
|
||||||
// Iconic state
|
// Iconic state
|
||||||
TaskState state = (task_active && task->win == task_active->win ? TASK_ACTIVE : TASK_NORMAL);
|
TaskState state = (active_task && task->win == active_task->win ? TASK_ACTIVE : TASK_NORMAL);
|
||||||
if (window_is_iconified(win))
|
if (window_is_iconified(win))
|
||||||
state = TASK_ICONIFIED;
|
state = TASK_ICONIFIED;
|
||||||
set_task_state(task, state);
|
set_task_state(task, state);
|
||||||
@@ -855,10 +911,7 @@ void event_property_notify(XEvent *e)
|
|||||||
// printf(" Window desktop changed %d, %d\n", task->desktop, desktop);
|
// printf(" Window desktop changed %d, %d\n", task->desktop, desktop);
|
||||||
// bug in windowmaker : send unecessary 'desktop changed' when focus changed
|
// bug in windowmaker : send unecessary 'desktop changed' when focus changed
|
||||||
if (desktop != task->desktop) {
|
if (desktop != task->desktop) {
|
||||||
remove_task(task);
|
update_task_desktop(task);
|
||||||
task = add_task(win);
|
|
||||||
active_task();
|
|
||||||
panel_refresh = TRUE;
|
|
||||||
}
|
}
|
||||||
} else if (at == server.atom.WM_HINTS) {
|
} else if (at == server.atom.WM_HINTS) {
|
||||||
XWMHints *wmhints = XGetWMHints(server.dsp, win);
|
XWMHints *wmhints = XGetWMHints(server.dsp, win);
|
||||||
@@ -917,13 +970,23 @@ void event_configure_notify(XEvent *e)
|
|||||||
task = add_task(win);
|
task = add_task(win);
|
||||||
if (win == get_active_window()) {
|
if (win == get_active_window()) {
|
||||||
set_task_state(task, TASK_ACTIVE);
|
set_task_state(task, TASK_ACTIVE);
|
||||||
task_active = task;
|
active_task = task;
|
||||||
}
|
}
|
||||||
panel_refresh = TRUE;
|
panel_refresh = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.viewports) {
|
||||||
|
Task *task = task_get_task(win);
|
||||||
|
if (task) {
|
||||||
|
int desktop = get_window_desktop(win);
|
||||||
|
if (task->desktop != desktop) {
|
||||||
|
update_task_desktop(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort_taskbar_for_win(win);
|
sort_taskbar_for_win(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ typedef enum MouseAction {
|
|||||||
PREV_TASK
|
PREV_TASK
|
||||||
} MouseAction;
|
} MouseAction;
|
||||||
|
|
||||||
#define ALLDESKTOP 0xFFFFFFFF
|
#define ALL_DESKTOPS 0xFFFFFFFF
|
||||||
|
|
||||||
// Copies a file to another path
|
// Copies a file to another path
|
||||||
void copy_file(const char *path_src, const char *path_dest);
|
void copy_file(const char *path_src, const char *path_dest);
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ void activate_window(Window win)
|
|||||||
send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0);
|
send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void change_desktop(int desktop)
|
|
||||||
{
|
|
||||||
send_event32(server.root_win, server.atom._NET_CURRENT_DESKTOP, desktop, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void change_window_desktop(Window win, int desktop)
|
void change_window_desktop(Window win, int desktop)
|
||||||
{
|
{
|
||||||
send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0);
|
send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0);
|
||||||
@@ -113,7 +108,53 @@ gboolean window_is_hidden(Window win)
|
|||||||
|
|
||||||
int get_window_desktop(Window win)
|
int get_window_desktop(Window win)
|
||||||
{
|
{
|
||||||
return get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
|
if (!server.viewports)
|
||||||
|
return get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
|
||||||
|
|
||||||
|
int x, y, w, h;
|
||||||
|
get_window_coordinates(win, &x, &y, &w, &h);
|
||||||
|
|
||||||
|
int desktop = MIN(get_current_desktop(), server.num_desktops - 1);
|
||||||
|
// Window coordinates are relative to the current viewport, make them absolute
|
||||||
|
x += server.viewports[desktop].x;
|
||||||
|
y += server.viewports[desktop].y;
|
||||||
|
|
||||||
|
if (x < 0 || y < 0) {
|
||||||
|
int num_results;
|
||||||
|
long *x_screen_size = server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
|
||||||
|
if (!x_screen_size)
|
||||||
|
return 0;
|
||||||
|
int x_screen_width = x_screen_size[0];
|
||||||
|
int x_screen_height = x_screen_size[1];
|
||||||
|
XFree(x_screen_size);
|
||||||
|
|
||||||
|
// Wrap
|
||||||
|
if (x < 0)
|
||||||
|
x += x_screen_width;
|
||||||
|
if (y < 0)
|
||||||
|
y += x_screen_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int best_match = -1;
|
||||||
|
int match_right = 0;
|
||||||
|
int match_bottom = 0;
|
||||||
|
// There is an ambiguity when a window is right on the edge between viewports.
|
||||||
|
// In that case, prefer the viewports which is on the right and bottom of the window's top-left corner.
|
||||||
|
for (int i = 0; i < server.num_desktops; i++) {
|
||||||
|
if (x >= server.viewports[i].x && x <= (server.viewports[i].x + server.viewports[i].width) &&
|
||||||
|
y >= server.viewports[i].y && y <= (server.viewports[i].y + server.viewports[i].height)) {
|
||||||
|
int current_right = x < (server.viewports[i].x + server.viewports[i].width);
|
||||||
|
int current_bottom = y < (server.viewports[i].y + server.viewports[i].height);
|
||||||
|
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||||
|
best_match = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_match < 0)
|
||||||
|
best_match = 0;
|
||||||
|
// printf("window %lx : viewport %d, (%d, %d)\n", win, best_match+1, x, y);
|
||||||
|
return best_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_window_monitor(Window win)
|
int get_window_monitor(Window win)
|
||||||
@@ -128,14 +169,14 @@ int get_window_monitor(Window win)
|
|||||||
// There is an ambiguity when a window is right on the edge between screens.
|
// There is an ambiguity when a window is right on the edge between screens.
|
||||||
// In that case, prefer the monitor which is on the right and bottom of the window's top-left corner.
|
// In that case, prefer the monitor which is on the right and bottom of the window's top-left corner.
|
||||||
for (i = 0; i < server.num_monitors; i++) {
|
for (i = 0; i < server.num_monitors; i++) {
|
||||||
if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width))
|
if (x >= server.monitor[i].x && x <= (server.monitor[i].x + server.monitor[i].width) &&
|
||||||
if (y >= server.monitor[i].y && y <= (server.monitor[i].y + server.monitor[i].height)) {
|
y >= server.monitor[i].y && y <= (server.monitor[i].y + server.monitor[i].height)) {
|
||||||
int current_right = x < (server.monitor[i].x + server.monitor[i].width);
|
int current_right = x < (server.monitor[i].x + server.monitor[i].width);
|
||||||
int current_bottom = y < (server.monitor[i].y + server.monitor[i].height);
|
int current_bottom = y < (server.monitor[i].y + server.monitor[i].height);
|
||||||
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
|
||||||
best_match = i;
|
best_match = i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_match < 0)
|
if (best_match < 0)
|
||||||
@@ -201,29 +242,6 @@ gboolean window_is_skip_taskbar(Window win)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSList *get_desktop_names()
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
GSList *list = NULL;
|
|
||||||
gchar *data_ptr = server_get_property(server.root_win, server.atom._NET_DESKTOP_NAMES, server.atom.UTF8_STRING, &count);
|
|
||||||
if (data_ptr) {
|
|
||||||
list = g_slist_append(list, g_strdup(data_ptr));
|
|
||||||
for (int j = 0; j < count - 1; j++) {
|
|
||||||
if (*(data_ptr + j) == '\0') {
|
|
||||||
gchar *ptr = (gchar *)data_ptr + j + 1;
|
|
||||||
list = g_slist_append(list, g_strdup(ptr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XFree(data_ptr);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_current_desktop()
|
|
||||||
{
|
|
||||||
return get_property32(server.root_win, server.atom._NET_CURRENT_DESKTOP, XA_CARDINAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Window get_active_window()
|
Window get_active_window()
|
||||||
{
|
{
|
||||||
return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
|
return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
|
||||||
|
|||||||
@@ -13,10 +13,6 @@
|
|||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
GSList *get_desktop_names();
|
|
||||||
int get_current_desktop();
|
|
||||||
void change_desktop(int desktop);
|
|
||||||
|
|
||||||
Window get_active_window();
|
Window get_active_window();
|
||||||
|
|
||||||
gboolean window_is_iconified(Window win);
|
gboolean window_is_iconified(Window win);
|
||||||
|
|||||||
Reference in New Issue
Block a user