Allow moving fullscreen windows between monitors
[openbox.git] / openbox / actions / showmenu.c
blob7411e981c268c4e6a9aaf14b8396ba38f70dcd31
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 "openbox/config.h"
7 #include <glib.h>
9 typedef struct {
10 gchar *name;
11 GravityPoint position;
12 ObPlaceMonitor monitor_type;
13 gint monitor;
14 gboolean use_position;
15 } Options;
17 static gpointer setup_func(xmlNodePtr node);
18 static void free_func(gpointer options);
19 static gboolean run_func(ObActionsData *data, gpointer options);
21 void action_showmenu_startup(void)
23 actions_register("ShowMenu", setup_func, free_func, run_func);
26 static gpointer setup_func(xmlNodePtr node)
28 xmlNodePtr n, c;
29 Options *o;
30 gboolean x_pos_given = FALSE;
32 o = g_slice_new0(Options);
33 o->monitor = -1;
35 if ((n = obt_xml_find_node(node, "menu")))
36 o->name = obt_xml_node_string(n);
38 if ((n = obt_xml_find_node(node, "position"))) {
39 if ((c = obt_xml_find_node(n->children, "x"))) {
40 if (!obt_xml_node_contains(c, "default")) {
41 config_parse_gravity_coord(c, &o->position.x);
42 x_pos_given = TRUE;
46 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
47 if (!obt_xml_node_contains(c, "default")) {
48 config_parse_gravity_coord(c, &o->position.y);
49 o->use_position = TRUE;
53 /* unlike client placement, x/y is needed to specify a monitor,
54 * either it's under the mouse or it's in an exact actual position */
55 if (o->use_position && (c = obt_xml_find_node(n->children, "monitor"))) {
56 if (!obt_xml_node_contains(c, "default")) {
57 gchar *s = obt_xml_node_string(c);
58 if (!g_ascii_strcasecmp(s, "mouse"))
59 o->monitor_type = OB_PLACE_MONITOR_MOUSE;
60 else if (!g_ascii_strcasecmp(s, "active"))
61 o->monitor_type = OB_PLACE_MONITOR_ACTIVE;
62 else if (!g_ascii_strcasecmp(s, "primary"))
63 o->monitor_type = OB_PLACE_MONITOR_PRIMARY;
64 else if (!g_ascii_strcasecmp(s, "all"))
65 o->monitor_type = OB_PLACE_MONITOR_ALL;
66 else
67 o->monitor = obt_xml_node_int(c) - 1;
68 g_free(s);
72 return o;
75 static void free_func(gpointer options)
77 Options *o = options;
78 g_free(o->name);
79 g_slice_free(Options, o);
82 /* Always return FALSE because its not interactive */
83 static gboolean run_func(ObActionsData *data, gpointer options)
85 Options *o = options;
86 GravityPoint position = { { 0, }, };
87 gint monitor = -1;
89 if (o->use_position) {
90 if (o->monitor >= 0)
91 monitor = o->monitor;
92 else switch (o->monitor_type) {
93 case OB_PLACE_MONITOR_ANY:
94 case OB_PLACE_MONITOR_PRIMARY:
95 monitor = screen_monitor_primary(FALSE);
96 break;
97 case OB_PLACE_MONITOR_MOUSE:
98 monitor = screen_monitor_pointer();
99 break;
100 case OB_PLACE_MONITOR_ACTIVE:
101 monitor = screen_monitor_active();
102 break;
103 case OB_PLACE_MONITOR_ALL:
104 monitor = screen_num_monitors;
105 break;
106 default:
107 g_assert_not_reached();
110 position = o->position;
111 } else {
112 const Rect *allmon;
113 monitor = screen_num_monitors;
114 allmon = screen_physical_area_monitor(monitor);
115 position.x.pos = data->x - allmon->x;
116 position.y.pos = data->y - allmon->y;
119 /* you cannot call ShowMenu from inside a menu */
120 if (data->uact != OB_USER_ACTION_MENU_SELECTION && o->name)
121 menu_show(o->name, &position, monitor,
122 data->button != 0, o->use_position, data->client);
124 return FALSE;