Mouse effects: highlight clickable areas even when the mouse is on the panel border

This commit is contained in:
o9000 2016-02-27 13:41:36 +01:00
parent b038b58015
commit 0a77293f7d
12 changed files with 105 additions and 109 deletions

View file

@ -153,6 +153,7 @@ void init_battery_panel(void *p)
battery->area._draw_foreground = draw_battery;
battery->area.size_mode = LAYOUT_FIXED;
battery->area._resize = resize_battery;
battery->area._is_under_mouse = full_width_area_is_under_mouse;
battery->area.on_screen = TRUE;
battery->area.resize_needed = 1;
battery->area.has_mouse_over_effect = panel_config.mouse_effects &&

View file

@ -180,6 +180,7 @@ void init_clock_panel(void *p)
clock_init_fonts();
clock->area.parent = p;
clock->area.panel = p;
clock->area._is_under_mouse = full_width_area_is_under_mouse;
clock->area.has_mouse_press_effect = clock->area.has_mouse_over_effect =
panel_config.mouse_effects && (clock_lclick_command || clock_mclick_command || clock_rclick_command || clock_uwheel_command ||
clock_dwheel_command);

View file

@ -162,6 +162,7 @@ void init_execp_panel(void *p)
execp->area.size_mode = LAYOUT_FIXED;
execp->area._resize = resize_execp;
execp->area._get_tooltip_text = execp_get_tooltip;
execp->area._is_under_mouse = full_width_area_is_under_mouse;
execp->area.has_mouse_press_effect = panel_config.mouse_effects && (execp->area.has_mouse_over_effect =
execp->backend->lclick_command || execp->backend->mclick_command || execp->backend->rclick_command ||
execp->backend->uwheel_command || execp->backend->dwheel_command);

View file

@ -740,18 +740,10 @@ Panel *get_panel(Window win)
Taskbar *click_taskbar(Panel *panel, int x, int y)
{
if (panel_horizontal) {
for (int i = 0; i < panel->num_desktops; i++) {
Taskbar *taskbar = &panel->taskbar[i];
if (taskbar->area.on_screen && x >= taskbar->area.posx && x <= (taskbar->area.posx + taskbar->area.width))
return taskbar;
}
} else {
for (int i = 0; i < panel->num_desktops; i++) {
Taskbar *taskbar = &panel->taskbar[i];
if (taskbar->area.on_screen && y >= taskbar->area.posy && y <= (taskbar->area.posy + taskbar->area.height))
return taskbar;
}
for (int i = 0; i < panel->num_desktops; i++) {
Taskbar *taskbar = &panel->taskbar[i];
if (area_is_under_mouse(taskbar, x, y))
return taskbar;
}
return NULL;
}
@ -760,25 +752,13 @@ Task *click_task(Panel *panel, int x, int y)
{
Taskbar *taskbar = click_taskbar(panel, x, y);
if (taskbar) {
if (panel_horizontal) {
GList *l = taskbar->area.children;
if (taskbarname_enabled)
l = l->next;
for (; l; l = l->next) {
Task *task = (Task *)l->data;
if (task->area.on_screen && x >= task->area.posx && x <= (task->area.posx + task->area.width)) {
return task;
}
}
} else {
GList *l = taskbar->area.children;
if (taskbarname_enabled)
l = l->next;
for (; l; l = l->next) {
Task *task = (Task *)l->data;
if (task->area.on_screen && y >= task->area.posy && y <= (task->area.posy + task->area.height)) {
return task;
}
GList *l = taskbar->area.children;
if (taskbarname_enabled)
l = l->next;
for (; l; l = l->next) {
Task *task = (Task *)l->data;
if (area_is_under_mouse(task, x, y)) {
return task;
}
}
}
@ -789,108 +769,53 @@ Launcher *click_launcher(Panel *panel, int x, int y)
{
Launcher *launcher = &panel->launcher;
if (panel_horizontal) {
if (launcher->area.on_screen && x >= launcher->area.posx && x <= (launcher->area.posx + launcher->area.width))
return launcher;
} else {
if (launcher->area.on_screen && y >= launcher->area.posy && y <= (launcher->area.posy + launcher->area.height))
return launcher;
}
if (area_is_under_mouse(launcher, x, y))
return launcher;
return NULL;
}
LauncherIcon *click_launcher_icon(Panel *panel, int x, int y)
{
Launcher *launcher = click_launcher(panel, x, y);
if (launcher) {
for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *icon = (LauncherIcon *)l->data;
if (x >= (launcher->area.posx + icon->x) && x <= (launcher->area.posx + icon->x + icon->icon_size) &&
y >= (launcher->area.posy + icon->y) && y <= (launcher->area.posy + icon->y + icon->icon_size)) {
if (area_is_under_mouse(icon, x, y))
return icon;
}
}
}
return NULL;
}
gboolean click_padding(Panel *panel, int x, int y)
{
if (panel_horizontal) {
if (x < panel->area.paddingxlr || x > panel->area.width - panel->area.paddingxlr)
return TRUE;
} else {
if (y < panel->area.paddingxlr || y > panel->area.height - panel->area.paddingxlr)
return TRUE;
}
return FALSE;
}
int click_clock(Panel *panel, int x, int y)
Clock *click_clock(Panel *panel, int x, int y)
{
Clock *clock = &panel->clock;
if (panel_horizontal) {
if (clock->area.on_screen && x >= clock->area.posx && x <= (clock->area.posx + clock->area.width))
return TRUE;
} else {
if (clock->area.on_screen && y >= clock->area.posy && y <= (clock->area.posy + clock->area.height))
return TRUE;
}
return FALSE;
if (area_is_under_mouse(clock, x, y))
return clock;
return NULL;
}
#ifdef ENABLE_BATTERY
int click_battery(Panel *panel, int x, int y)
Battery *click_battery(Panel *panel, int x, int y)
{
Battery *bat = &panel->battery;
if (panel_horizontal) {
if (bat->area.on_screen && x >= bat->area.posx && x <= (bat->area.posx + bat->area.width))
return TRUE;
} else {
if (bat->area.on_screen && y >= bat->area.posy && y <= (bat->area.posy + bat->area.height))
return TRUE;
}
return FALSE;
if (area_is_under_mouse(bat, x, y))
return bat;
return NULL;
}
#endif
Execp *click_execp(Panel *panel, int x, int y)
{
GList *l;
for (l = panel->execp_list; l; l = l->next) {
for (GList *l = panel->execp_list; l; l = l->next) {
Execp *execp = (Execp *)l->data;
if (panel_horizontal) {
if (execp->area.on_screen && x >= execp->area.posx && x <= (execp->area.posx + execp->area.width))
return execp;
} else {
if (execp->area.on_screen && y >= execp->area.posy && y <= (execp->area.posy + execp->area.height))
return execp;
}
if (area_is_under_mouse(execp, x, y))
return execp;
}
return NULL;
}
Area *click_area(Panel *panel, int x, int y)
{
Area *result = &panel->area;
Area *new_result = result;
do {
result = new_result;
GList *it = result->children;
while (it) {
Area *a = (Area *)it->data;
if (a->on_screen && x >= a->posx && x <= (a->posx + a->width) && y >= a->posy &&
y <= (a->posy + a->height)) {
new_result = a;
break;
}
it = it->next;
}
} while (new_result != result);
return result;
}
void stop_autohide_timeout(Panel *p)
{
stop_timeout(p->autohide_timeout);

View file

@ -166,11 +166,10 @@ Taskbar *click_taskbar(Panel *panel, int x, int y);
Task *click_task(Panel *panel, int x, int y);
Launcher *click_launcher(Panel *panel, int x, int y);
LauncherIcon *click_launcher_icon(Panel *panel, int x, int y);
gboolean click_padding(Panel *panel, int x, int y);
gboolean click_clock(Panel *panel, int x, int y);
Clock *click_clock(Panel *panel, int x, int y);
#ifdef ENABLE_BATTERY
gboolean click_battery(Panel *panel, int x, int y);
Battery *click_battery(Panel *panel, int x, int y);
#endif
Area *click_area(Panel *panel, int x, int y);

View file

@ -67,6 +67,7 @@ Task *add_task(Window win)
memset(&task_template, 0, sizeof(task_template));
task_template.area.has_mouse_over_effect = panel_config.mouse_effects;
task_template.area.has_mouse_press_effect = panel_config.mouse_effects;
task_template.area._is_under_mouse = full_width_area_is_under_mouse;
task_template.win = win;
task_template.desktop = get_window_desktop(win);
task_template.area.panel = &panels[monitor];
@ -95,6 +96,7 @@ Task *add_task(Window win)
memcpy(&task_instance->area, &panels[monitor].g_task.area, sizeof(Area));
task_instance->area.has_mouse_over_effect = panel_config.mouse_effects;
task_instance->area.has_mouse_press_effect = panel_config.mouse_effects;
task_instance->area._is_under_mouse = full_width_area_is_under_mouse;
task_instance->win = task_template.win;
task_instance->desktop = task_template.desktop;
task_instance->win_x = task_template.win_x;

View file

@ -149,6 +149,7 @@ void init_taskbar_panel(void *p)
panel->g_taskbar.area_name.panel = panel;
panel->g_taskbar.area_name.size_mode = LAYOUT_FIXED;
panel->g_taskbar.area_name._resize = resize_taskbarname;
panel->g_taskbar.area_name._is_under_mouse = full_width_area_is_under_mouse;
panel->g_taskbar.area_name._draw_foreground = draw_taskbarname;
panel->g_taskbar.area_name._on_change_layout = 0;
panel->g_taskbar.area_name.resize_needed = 1;
@ -160,6 +161,7 @@ void init_taskbar_panel(void *p)
panel->g_taskbar.area.size_mode = LAYOUT_DYNAMIC;
panel->g_taskbar.area.alignment = taskbar_alignment;
panel->g_taskbar.area._resize = resize_taskbar;
panel->g_taskbar.area._is_under_mouse = full_width_area_is_under_mouse;
panel->g_taskbar.area.resize_needed = 1;
panel->g_taskbar.area.on_screen = TRUE;
if (panel_horizontal) {

View file

@ -89,4 +89,6 @@ void sort_taskbar_for_win(Window win);
void sort_tasks(Taskbar *taskbar);
gboolean taskbar_is_under_mouse(void *obj, int x, int y);
#endif

View file

@ -1616,7 +1616,7 @@ start:
case ButtonPress: {
tooltip_hide(0);
event_button_press(&e);
Area *area = click_area(panel, e.xbutton.x, e.xbutton.y);
Area *area = find_area_under_mouse(panel, e.xbutton.x, e.xbutton.y);
if (panel_config.mouse_effects)
mouse_over(area, 1);
break;
@ -1624,7 +1624,7 @@ start:
case ButtonRelease: {
event_button_release(&e);
Area *area = click_area(panel, e.xbutton.x, e.xbutton.y);
Area *area = find_area_under_mouse(panel, e.xbutton.x, e.xbutton.y);
if (panel_config.mouse_effects)
mouse_over(area, 0);
break;
@ -1635,7 +1635,7 @@ start:
if (e.xmotion.state & button_mask)
event_button_motion_notify(&e);
Area *area = click_area(panel, e.xmotion.x, e.xmotion.y);
Area *area = find_area_under_mouse(panel, e.xmotion.x, e.xmotion.y);
if (area->_get_tooltip_text)
tooltip_trigger_show(area, panel, &e);
else

View file

@ -132,7 +132,7 @@ void tooltip_show(void *arg)
int mx, my;
Window w;
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
Area *area = click_area(g_tooltip.panel, mx, my);
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
if (!g_tooltip.mapped && area->_get_tooltip_text) {
tooltip_copy_text(area);
g_tooltip.mapped = True;

View file

@ -564,3 +564,49 @@ void mouse_out()
panel_refresh = TRUE;
mouse_over_area = NULL;
}
gboolean area_is_under_mouse(void *obj, int x, int y)
{
Area *a = obj;
if (!a->on_screen)
return FALSE;
if (a->_is_under_mouse)
return a->_is_under_mouse(a, x, y);
return x >= a->posx && x <= (a->posx + a->width) && y >= a->posy && y <= (a->posy + a->height);
}
gboolean full_width_area_is_under_mouse(void *obj, int x, int y)
{
Area *a = obj;
if (!a->on_screen)
return FALSE;
if (a->_is_under_mouse && a->_is_under_mouse != full_width_area_is_under_mouse)
return a->_is_under_mouse(a, x, y);
if (panel_horizontal)
return x >= a->posx && x <= a->posx + a->width;
else
return y >= a->posy && y <= a->posy + a->height;
}
Area *find_area_under_mouse(void *root, int x, int y)
{
Area *result = root;
Area *new_result = result;
do {
result = new_result;
GList *it = result->children;
while (it) {
Area *a = (Area *)it->data;
if (area_is_under_mouse(a, x, y)) {
new_result = a;
break;
}
it = it->next;
}
} while (new_result != result);
return result;
}

View file

@ -219,6 +219,10 @@ typedef struct Area {
// Returns a copy of the tooltip to be displayed for this widget.
// The caller takes ownership of the pointer.
char *(*_get_tooltip_text)(void *obj);
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
// Leave this to NULL to use a default implementation.
gboolean (*_is_under_mouse)(void *obj, int x, int y);
} Area;
// Initializes the Background member to default values.
@ -266,7 +270,20 @@ void add_area(Area *a, Area *parent);
void remove_area(Area *a);
void free_area(Area *a);
// Mouse move events
// Mouse events
// Returns the area under the mouse for the given x, y mouse coordinates relative to the window.
// If no area is found, returns the root.
Area *find_area_under_mouse(void *root, int x, int y);
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
gboolean area_is_under_mouse(void *obj, int x, int y);
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
// The Area will also handle clicks on the border of its ancestors, including the panel.
// Useful so that a click at the edge of the screen is still handled by task buttons etc., even if technically
// they are outside the drawing area of the button.
gboolean full_width_area_is_under_mouse(void *obj, int x, int y);
void mouse_over(Area *area, int pressed);
void mouse_out();