Mouse effects: highlight clickable areas even when the mouse is on the panel border
This commit is contained in:
parent
b038b58015
commit
0a77293f7d
12 changed files with 105 additions and 109 deletions
|
@ -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 &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
127
src/panel.c
127
src/panel.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue