Allow moving fullscreen windows between monitors
[mikachu/openbox.git] / openbox / actions / layer.c
1 #include "openbox/actions.h"
2 #include "openbox/client.h"
3
4 typedef struct {
5     gint layer; /*!< -1 for below, 0 for normal, and 1 for above */
6     gboolean toggle;
7 } Options;
8
9 static gpointer setup_func_top(xmlNodePtr node);
10 static gpointer setup_func_bottom(xmlNodePtr node);
11 static gpointer setup_func_send(xmlNodePtr node);
12 static void free_func(gpointer o);
13 static gboolean run_func(ObActionsData *data, gpointer options);
14 /* 3.4-compatibility */
15 static gpointer setup_sendtop_func(xmlNodePtr node);
16 static gpointer setup_sendbottom_func(xmlNodePtr node);
17 static gpointer setup_sendnormal_func(xmlNodePtr node);
18
19 void action_layer_startup(void)
20 {
21     actions_register("ToggleAlwaysOnTop", setup_func_top, free_func,
22                      run_func);
23     actions_register("ToggleAlwaysOnBottom", setup_func_bottom, free_func,
24                      run_func);
25     actions_register("SendToLayer", setup_func_send, free_func,
26                      run_func);
27     /* 3.4-compatibility */
28     actions_register("SendToTopLayer", setup_sendtop_func, free_func,
29                      run_func);
30     actions_register("SendToBottomLayer", setup_sendbottom_func, free_func,
31                      run_func);
32     actions_register("SendToNormalLayer", setup_sendnormal_func, free_func,
33                      run_func);
34 }
35
36 static gpointer setup_func_top(xmlNodePtr node)
37 {
38     Options *o = g_slice_new0(Options);
39     o->layer = 1;
40     o->toggle = TRUE;
41     return o;
42 }
43
44 static gpointer setup_func_bottom(xmlNodePtr node)
45 {
46     Options *o = g_slice_new0(Options);
47     o->layer = -1;
48     o->toggle = TRUE;
49     return o;
50 }
51
52 static gpointer setup_func_send(xmlNodePtr node)
53 {
54     xmlNodePtr n;
55     Options *o;
56
57     o = g_slice_new0(Options);
58
59     if ((n = obt_xml_find_node(node, "layer"))) {
60         gchar *s = obt_xml_node_string(n);
61         if (!g_ascii_strcasecmp(s, "above") ||
62             !g_ascii_strcasecmp(s, "top"))
63             o->layer = 1;
64         else if (!g_ascii_strcasecmp(s, "below") ||
65                  !g_ascii_strcasecmp(s, "bottom"))
66             o->layer = -1;
67         else if (!g_ascii_strcasecmp(s, "normal") ||
68                  !g_ascii_strcasecmp(s, "middle"))
69             o->layer = 0;
70         g_free(s);
71     }
72
73     return o;
74 }
75
76 static void free_func(gpointer o)
77 {
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
86     if (data->client) {
87         ObClient *c = data->client;
88
89         actions_client_move(data, TRUE);
90
91         if (o->layer < 0) {
92             if (o->toggle || !c->below)
93                 client_set_layer(c, c->below ? 0 : -1);
94         }
95         else if (o->layer > 0) {
96             if (o->toggle || !c->above)
97                 client_set_layer(c, c->above ? 0 : 1);
98         }
99         else if (c->above || c->below)
100             client_set_layer(c, 0);
101
102         actions_client_move(data, FALSE);
103     }
104
105     return FALSE;
106 }
107
108 /* 3.4-compatibility */
109 static gpointer setup_sendtop_func(xmlNodePtr node)
110 {
111     Options *o = g_slice_new0(Options);
112     o->layer = 1;
113     o->toggle = FALSE;
114     return o;
115 }
116
117 static gpointer setup_sendbottom_func(xmlNodePtr node)
118 {
119     Options *o = g_slice_new0(Options);
120     o->layer = -1;
121     o->toggle = FALSE;
122     return o;
123 }
124
125 static gpointer setup_sendnormal_func(xmlNodePtr node)
126 {
127     Options *o = g_slice_new0(Options);
128     o->layer = 0;
129     o->toggle = FALSE;
130     return o;
131 }
132