1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#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;
GravityPoint position;
ObPlaceMonitor monitor_type;
gint monitor;
gboolean use_position;
} Options;
static gpointer setup_func(xmlNodePtr node);
static void free_func(gpointer options);
static gboolean run_func(ObActionsData *data, gpointer options);
void action_showmenu_startup(void)
{
actions_register("ShowMenu", setup_func, free_func, run_func);
}
static gpointer setup_func(xmlNodePtr node)
{
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->position.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->position.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;
}
static void free_func(gpointer options)
{
Options *o = options;
g_free(o->name);
g_slice_free(Options, o);
}
/* Always return FALSE because its not interactive */
static gboolean run_func(ObActionsData *data, gpointer options)
{
Options *o = options;
GravityPoint position = { 0, };
gint monitor = -1;
if (o->use_position) {
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();
}
position = o->position;
} else {
monitor = screen_num_monitors;
position.x.pos = data->x;
position.y.pos = data->y;
}
/* you cannot call ShowMenu from inside a menu */
if (data->uact != OB_USER_ACTION_MENU_SELECTION && o->name)
menu_show(o->name, position, monitor,
data->button != 0, o->use_position, data->client);
return FALSE;
}
|