Resolve gravity coords in menuframe so it can use the widths
[dana/openbox.git] / openbox / actions / showmenu.c
1 #include "openbox/actions.h"
2 #include "openbox/menu.h"
3 #include "openbox/place.h"
4 #include "openbox/geom.h"
5 #include "openbox/screen.h"
6 #include <glib.h>
7
8 typedef struct {
9     gchar         *name;
10     GravityPoint   position;
11     ObPlaceMonitor monitor_type;
12     gint           monitor;
13     gboolean       use_position;
14 } Options;
15
16 static gpointer setup_func(xmlNodePtr node);
17 static void     free_func(gpointer options);
18 static gboolean run_func(ObActionsData *data, gpointer options);
19
20 void action_showmenu_startup(void)
21 {
22     actions_register("ShowMenu", setup_func, free_func, run_func);
23 }
24
25 static gpointer setup_func(xmlNodePtr node)
26 {
27     xmlNodePtr n, c;
28     Options *o;
29     gboolean x_pos_given = FALSE;
30
31     o = g_slice_new0(Options);
32     o->monitor = -1;
33
34     if ((n = obt_xml_find_node(node, "menu")))
35         o->name = obt_xml_node_string(n);
36
37     if ((n = obt_xml_find_node(node, "position"))) {
38         if ((c = obt_xml_find_node(n->children, "x"))) {
39             if (!obt_xml_node_contains(c, "default")) {
40                 config_parse_gravity_coord(c, &o->position.x);
41                 x_pos_given = TRUE;
42             }
43         }
44
45         if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
46             if (!obt_xml_node_contains(c, "default")) {
47                 config_parse_gravity_coord(c, &o->position.y);
48                 o->use_position = TRUE;
49             }
50         }
51
52         /* unlike client placement, x/y is needed to specify a monitor,
53          * either it's under the mouse or it's in an exact actual position */
54         if (o->use_position && (c = obt_xml_find_node(n->children, "monitor"))) {
55             if (!obt_xml_node_contains(c, "default")) {
56                 gchar *s = obt_xml_node_string(c);
57                 if (!g_ascii_strcasecmp(s, "mouse"))
58                     o->monitor_type = OB_PLACE_MONITOR_MOUSE;
59                 else if (!g_ascii_strcasecmp(s, "active"))
60                     o->monitor_type = OB_PLACE_MONITOR_ACTIVE;
61                 else if (!g_ascii_strcasecmp(s, "primary"))
62                     o->monitor_type = OB_PLACE_MONITOR_PRIMARY;
63                 else if (!g_ascii_strcasecmp(s, "all"))
64                     o->monitor_type = OB_PLACE_MONITOR_ALL;
65                 else
66                     o->monitor = obt_xml_node_int(c) - 1;
67                 g_free(s);
68             }
69         }
70     }
71     return o;
72 }
73
74 static void free_func(gpointer options)
75 {
76     Options *o = options;
77     g_free(o->name);
78     g_slice_free(Options, o);
79 }
80
81 /* Always return FALSE because its not interactive */
82 static gboolean run_func(ObActionsData *data, gpointer options)
83 {
84     Options *o = options;
85     GravityPoint position = { 0, };
86     gint monitor = -1;
87
88     if (o->use_position) {
89         if (o->monitor >= 0)
90             monitor = o->monitor;
91         else switch (o->monitor_type) {
92             case OB_PLACE_MONITOR_ANY:
93             case OB_PLACE_MONITOR_PRIMARY:
94                 monitor = screen_monitor_primary(FALSE);
95                 break;
96             case OB_PLACE_MONITOR_MOUSE:
97                 monitor = screen_monitor_pointer();
98                 break;
99             case OB_PLACE_MONITOR_ACTIVE:
100                 monitor = screen_monitor_active();
101                 break;
102             case OB_PLACE_MONITOR_ALL:
103                 monitor = screen_num_monitors;
104                 break;
105             default:
106                 g_assert_not_reached();
107         }
108
109         position = o->position;
110     } else {
111         monitor = screen_num_monitors;
112         position.x.pos = data->x;
113         position.y.pos = data->y;
114     }
115
116     /* you cannot call ShowMenu from inside a menu */
117     if (data->uact != OB_USER_ACTION_MENU_SELECTION && o->name)
118         menu_show(o->name, position, monitor, data->button != 0, data->client);
119
120     return FALSE;
121 }