Add <position> tag to ShowMenu action

This commit is contained in:
Mikael Magnusson 2014-10-06 18:21:38 +02:00
parent 2d289312ba
commit 238ab3f742
2 changed files with 106 additions and 4 deletions

View file

@ -1,9 +1,16 @@
#include "openbox/actions.h"
#include "openbox/menu.h"
#include "openbox/place.h"
#include "openbox/geom.h"
#include "openbox/screen.h"
#include <glib.h>
typedef struct {
gchar *name;
gchar *name;
GravityCoord x, y;
ObPlaceMonitor monitor_type;
gint monitor;
gboolean use_position;
} Options;
static gpointer setup_func(xmlNodePtr node);
@ -17,13 +24,50 @@ void action_showmenu_startup(void)
static gpointer setup_func(xmlNodePtr node)
{
xmlNodePtr n;
xmlNodePtr n, c;
Options *o;
gboolean x_pos_given = FALSE;
o = g_slice_new0(Options);
o->monitor = -1;
if ((n = obt_xml_find_node(node, "menu")))
o->name = obt_xml_node_string(n);
if ((n = obt_xml_find_node(node, "position"))) {
if ((c = obt_xml_find_node(n->children, "x"))) {
if (!obt_xml_node_contains(c, "default")) {
config_parse_gravity_coord(c, &o->x);
x_pos_given = TRUE;
}
}
if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
if (!obt_xml_node_contains(c, "default")) {
config_parse_gravity_coord(c, &o->y);
o->use_position = TRUE;
}
}
/* unlike client placement, x/y is needed to specify a monitor,
* either it's under the mouse or it's in an exact actual position */
if (o->use_position && (c = obt_xml_find_node(n->children, "monitor"))) {
if (!obt_xml_node_contains(c, "default")) {
gchar *s = obt_xml_node_string(c);
if (!g_ascii_strcasecmp(s, "mouse"))
o->monitor_type = OB_PLACE_MONITOR_MOUSE;
else if (!g_ascii_strcasecmp(s, "active"))
o->monitor_type = OB_PLACE_MONITOR_ACTIVE;
else if (!g_ascii_strcasecmp(s, "primary"))
o->monitor_type = OB_PLACE_MONITOR_PRIMARY;
else if (!g_ascii_strcasecmp(s, "all"))
o->monitor_type = OB_PLACE_MONITOR_ALL;
else
o->monitor = obt_xml_node_int(c) - 1;
g_free(s);
}
}
}
return o;
}
@ -34,14 +78,71 @@ static void free_func(gpointer options)
g_slice_free(Options, o);
}
static void calc_position(Options *o, gint *x, gint *y)
{
gint monitor = -1;
const Rect *area;
if (o->monitor >= 0)
monitor = o->monitor;
else switch (o->monitor_type) {
case OB_PLACE_MONITOR_ANY:
case OB_PLACE_MONITOR_PRIMARY:
monitor = screen_monitor_primary(FALSE);
break;
case OB_PLACE_MONITOR_MOUSE:
monitor = screen_monitor_pointer();
break;
case OB_PLACE_MONITOR_ACTIVE:
monitor = screen_monitor_active();
break;
case OB_PLACE_MONITOR_ALL:
monitor = screen_num_monitors;
break;
default:
g_assert_not_reached();
}
area = screen_physical_area_monitor(monitor);
if (o->x.center)
*x = area->width / 2; /* - client->area.width / 2; */
else {
*x = o->x.pos;
if (o->x.denom)
*x = (*x * area->width) / o->x.denom;
if (o->x.opposite)
*x = area->width /* - frame_size.width */ - *x;
}
if (o->y.center)
*y = area->height / 2; /* - client->area.height / 2; */
else {
*y = o->y.pos;
if (o->y.denom)
*y = (*y * area->height) / o->y.denom;
if (o->y.opposite)
*y = area->height /* - frame_size.height */ - *y;
}
*x += area->x;
*y += area->y;
}
/* Always return FALSE because its not interactive */
static gboolean run_func(ObActionsData *data, gpointer options)
{
Options *o = options;
gint x, y;
if (o->use_position) {
calc_position(o, &x, &y);
} else {
x = data->x;
y = data->y;
}
/* you cannot call ShowMenu from inside a menu */
if (data->uact != OB_USER_ACTION_MENU_SELECTION && o->name)
menu_show(o->name, data->x, data->y, data->button != 0, data->client);
menu_show(o->name, x, y, data->button != 0, data->client);
return FALSE;
}

View file

@ -38,7 +38,8 @@ typedef enum
OB_PLACE_MONITOR_ANY,
OB_PLACE_MONITOR_ACTIVE,
OB_PLACE_MONITOR_MOUSE,
OB_PLACE_MONITOR_PRIMARY
OB_PLACE_MONITOR_PRIMARY,
OB_PLACE_MONITOR_ALL
} ObPlaceMonitor;
/*! Return TRUE if openbox chose the position for the window, and FALSE if