Mouse effects: highlight clickable areas even when the mouse is on the panel border
@@ -153,6 +153,7 @@ battery->area.panel = 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 @@ clock->area.bg = &g_array_index(backgrounds, Background, 0);
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 @@ execp->area._draw_foreground = draw_execp;
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);
@@ -740,18 +740,10 @@ }
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,106 +769,51 @@ 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)
@@ -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 task_template;
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 *task_instance = calloc(1, sizeof(Task));
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 @@ // taskbar name
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 @@ panel->g_taskbar.area.panel = panel;
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 @@ switch (e.type) {
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 @@ }
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 @@ unsigned int button_mask = Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
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 @@ {
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 @@ mouse_over_area->_redraw_needed = TRUE;
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 @@
// 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();