]>
Dogcows Code - chaz/openbox/blob - plugins/mouse/mouse.c
5dd39db39d59597a02200e02ed929c06b92ec97e
1 #include "../../kernel/openbox.h"
2 #include "../../kernel/dispatch.h"
3 #include "../../kernel/action.h"
4 #include "../../kernel/client.h"
5 #include "../../kernel/frame.h"
6 #include "../../kernel/engine.h"
11 /* GData of GSList*s of PointerBinding*s. */
12 static GData
*bound_contexts
;
14 struct foreach_grab_temp
{
19 static void grab_button(Client
*client
, guint state
, guint button
,
20 GQuark context
, gboolean grab
)
23 int mode
= GrabModeAsync
;
26 if (context
== g_quark_try_string("frame")) {
27 win
= client
->frame
->window
;
28 mask
= ButtonPressMask
| ButtonMotionMask
| ButtonReleaseMask
;
29 } else if (context
== g_quark_try_string("client")) {
30 win
= client
->frame
->plate
;
31 mode
= GrabModeSync
; /* this is handled in pointer_event */
32 mask
= ButtonPressMask
; /* can't catch more than this with Sync mode
33 the release event is manufactured in
38 /* XXX grab all lock keys */
39 XGrabButton(ob_display
, button
, state
, win
, FALSE
, mask
, mode
,
40 GrabModeAsync
, None
, None
);
42 /* XXX ungrab all lock keys */
43 XUngrabButton(ob_display
, button
, state
, win
);
46 static void foreach_grab(GQuark key
, gpointer data
, gpointer user_data
)
48 struct foreach_grab_temp
*d
= user_data
;
50 for (it
= data
; it
!= NULL
; it
= it
->next
) {
51 MouseBinding
*b
= it
->data
;
52 grab_button(d
->client
, b
->state
, b
->button
, key
, d
->grab
);
56 static void grab_for_client(Client
*client
, gboolean grab
)
58 struct foreach_grab_temp bt
;
61 g_datalist_foreach(&bound_contexts
, foreach_grab
, &bt
);
64 static void grab_all_clients(gboolean grab
)
68 for (it
= client_list
; it
!= NULL
; it
= it
->next
)
69 grab_for_client(it
->data
, grab
);
72 static void foreach_clear(GQuark key
, gpointer data
, gpointer user_data
)
75 user_data
= user_data
;
76 for (it
= data
; it
!= NULL
; it
= it
->next
) {
79 MouseBinding
*b
= it
->data
;
80 for (i
= 0; i
< NUM_MOUSEACTION
; ++i
)
81 action_free(b
->action
[i
]);
87 static void fire_button(MouseAction a
, GQuark context
, Client
*c
, guint state
,
93 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
94 it
!= NULL
; it
= it
->next
) {
96 if (b
->state
== state
&& b
->button
== button
)
99 /* if not bound, then nothing to do! */
100 if (it
== NULL
) return;
102 if (b
->action
[a
] != NULL
&& b
->action
[a
]->func
!= NULL
) {
103 b
->action
[a
]->data
.any
.c
= c
;
105 g_assert(!(b
->action
[a
]->func
== action_move
||
106 b
->action
[a
]->func
== action_resize
));
108 b
->action
[a
]->func(&b
->action
[a
]->data
);
112 /* corner should be the opposite corner of the window in which the pointer
113 clicked, Corner_TopLeft if a good default if there is no client */
114 static void fire_motion(MouseAction a
, GQuark context
, Client
*c
, guint state
,
115 guint button
, int cx
, int cy
, int cw
, int ch
,
116 int dx
, int dy
, gboolean final
, Corner corner
)
121 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
122 it
!= NULL
; it
= it
->next
) {
124 if (b
->state
== state
&& b
->button
== button
)
127 /* if not bound, then nothing to do! */
128 if (it
== NULL
) return;
130 if (b
->action
[a
] != NULL
&& b
->action
[a
]->func
!= NULL
) {
131 b
->action
[a
]->data
.any
.c
= c
;
133 if (b
->action
[a
]->func
== action_move
) {
134 b
->action
[a
]->data
.move
.x
= cx
+ dx
;
135 b
->action
[a
]->data
.move
.y
= cy
+ dy
;
136 b
->action
[a
]->data
.move
.final
= final
;
137 } else if (b
->action
[a
]->func
== action_resize
) {
138 b
->action
[a
]->data
.resize
.corner
= corner
;
141 b
->action
[a
]->data
.resize
.x
= cw
+ dx
;
142 b
->action
[a
]->data
.resize
.y
= ch
+ dy
;
144 case Corner_TopRight
:
145 b
->action
[a
]->data
.resize
.x
= cw
- dx
;
146 b
->action
[a
]->data
.resize
.y
= ch
+ dy
;
148 case Corner_BottomLeft
:
149 b
->action
[a
]->data
.resize
.x
= cw
+ dx
;
150 b
->action
[a
]->data
.resize
.y
= ch
- dy
;
152 case Corner_BottomRight
:
153 b
->action
[a
]->data
.resize
.x
= cw
- dx
;
154 b
->action
[a
]->data
.resize
.y
= ch
- dy
;
157 b
->action
[a
]->data
.resize
.final
= final
;
159 b
->action
[a
]->func(&b
->action
[a
]->data
);
163 static Corner
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
165 if (x
- cx
< cw
/ 2) {
167 return Corner_BottomRight
;
169 return Corner_TopRight
;
172 return Corner_BottomLeft
;
174 return Corner_TopLeft
;
178 static void event(ObEvent
*e
, void *foo
)
181 static int px
, py
, cx
, cy
, cw
, ch
, dx
, dy
;
182 static guint button
= 0, lbutton
= 0;
183 static gboolean drag
= FALSE
;
184 static Corner corner
= Corner_TopLeft
;
185 gboolean click
= FALSE
;
186 gboolean dclick
= FALSE
;
189 case Event_Client_Mapped
:
190 grab_for_client(e
->data
.c
.client
, TRUE
);
193 case Event_Client_Destroy
:
194 grab_for_client(e
->data
.c
.client
, FALSE
);
197 case Event_X_ButtonPress
:
199 if (e
->data
.x
.client
== NULL
)
200 corner
= Corner_TopLeft
;
202 cx
= e
->data
.x
.client
->frame
->area
.x
;
203 cy
= e
->data
.x
.client
->frame
->area
.y
;
204 cw
= e
->data
.x
.client
->frame
->area
.width
;
205 ch
= e
->data
.x
.client
->frame
->area
.height
;
206 px
= e
->data
.x
.e
->xbutton
.x_root
;
207 py
= e
->data
.x
.e
->xbutton
.y_root
;
208 corner
= pick_corner(px
, py
, cx
, cy
, cw
, ch
);
209 button
= e
->data
.x
.e
->xbutton
.button
;
212 fire_button(MouseAction_Press
,
213 engine_get_context(e
->data
.x
.client
,
214 e
->data
.x
.e
->xbutton
.window
),
215 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
216 e
->data
.x
.e
->xbutton
.button
);
219 case Event_X_ButtonRelease
:
220 if (e
->data
.x
.e
->xbutton
.button
== button
) {
223 fire_motion(MouseAction_Motion
,
224 engine_get_context(e
->data
.x
.client
,
225 e
->data
.x
.e
->xbutton
.window
),
226 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
227 e
->data
.x
.e
->xbutton
.button
,
228 cx
, cy
, cw
, ch
, dx
, dy
, TRUE
, corner
);
231 /* clicks are only valid if its released over the window */
232 if (e
->data
.x
.e
->xbutton
.x
>= 0 && e
->data
.x
.e
->xbutton
.y
>= 0) {
236 XGetGeometry(ob_display
, e
->data
.x
.e
->xbutton
.window
,
237 &wjunk
, &junk
, &junk
, &w
, &h
, &ujunk
, &ujunk
);
238 if (e
->data
.x
.e
->xbutton
.x
< (signed)w
&&
239 e
->data
.x
.e
->xbutton
.y
< (signed)h
) {
241 /* double clicks happen if there were 2 in a row! */
242 if (lbutton
== button
&&
243 e
->data
.x
.e
->xbutton
.time
- 300 <= ltime
)
251 ltime
= e
->data
.x
.e
->xbutton
.time
;
253 fire_button(MouseAction_Press
,
254 engine_get_context(e
->data
.x
.client
,
255 e
->data
.x
.e
->xbutton
.window
),
256 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
257 e
->data
.x
.e
->xbutton
.button
);
259 fire_button(MouseAction_Click
,
260 engine_get_context(e
->data
.x
.client
,
261 e
->data
.x
.e
->xbutton
.window
),
262 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
263 e
->data
.x
.e
->xbutton
.button
);
265 fire_button(MouseAction_DClick
,
266 engine_get_context(e
->data
.x
.client
,
267 e
->data
.x
.e
->xbutton
.window
),
268 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
269 e
->data
.x
.e
->xbutton
.button
);
272 case Event_X_MotionNotify
:
275 dx
= e
->data
.x
.e
->xmotion
.x_root
- px
;
276 dy
= e
->data
.x
.e
->xmotion
.y_root
- py
;
277 fire_motion(MouseAction_Motion
,
278 engine_get_context(e
->data
.x
.client
,
279 e
->data
.x
.e
->xbutton
.window
),
280 e
->data
.x
.client
, e
->data
.x
.e
->xmotion
.state
,
281 button
, cx
, cy
, cw
, ch
, dx
, dy
, FALSE
, corner
);
286 g_assert_not_reached();
290 static gboolean
mbind(char *buttonstr
, char *contextstr
, MouseAction mact
,
299 if (!translate_button(buttonstr
, &state
, &button
)) {
300 g_warning("invalid button");
304 context
= g_quark_try_string(contextstr
);
306 g_warning("invalid context");
310 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
311 it
!= NULL
; it
= it
->next
){
313 if (b
->state
== state
&& b
->button
== button
) {
315 if (b
->action
[mact
] != NULL
) {
316 g_warning("duplicate binding");
319 b
->action
[mact
] = action
;
324 grab_all_clients(FALSE
);
326 /* add the binding */
327 b
= g_new(MouseBinding
, 1);
330 for (i
= 0; i
< NUM_MOUSEACTION
; ++i
)
333 b
->action
[mact
] = action
;
334 g_datalist_id_set_data(&bound_contexts
, context
,
335 g_slist_append(g_datalist_id_get_data(&bound_contexts
, context
), b
));
337 grab_all_clients(TRUE
);
342 static void binddef()
346 /* When creating an Action struct, all of the data elements in the
347 appropriate struct need to be set, except the Client*, which will be set
348 at call-time when then action function is used.
350 For action_move and action_resize, the 'x', 'y', and 'final' data
351 elements should not be set, as they are set at call-time.
354 a
= action_new(action_move
);
355 mbind("1", "titlebar", MouseAction_Motion
, a
);
356 a
= action_new(action_move
);
357 mbind("1", "handle", MouseAction_Motion
, a
);
358 a
= action_new(action_move
);
359 mbind("A-1", "frame", MouseAction_Motion
, a
);
361 a
= action_new(action_resize
);
362 mbind("1", "blcorner", MouseAction_Motion
, a
);
363 a
= action_new(action_resize
);
364 mbind("1", "brcorner", MouseAction_Motion
, a
);
365 a
= action_new(action_resize
);
366 mbind("A-3", "frame", MouseAction_Motion
, a
);
369 void plugin_startup()
371 dispatch_register(Event_Client_Mapped
| Event_Client_Destroy
|
372 Event_X_ButtonPress
| Event_X_ButtonRelease
|
373 Event_X_MotionNotify
, (EventHandler
)event
, NULL
);
375 /* XXX parse a config */
379 void plugin_shutdown()
381 dispatch_register(0, (EventHandler
)event
, NULL
);
383 grab_all_clients(FALSE
);
384 g_datalist_foreach(&bound_contexts
, foreach_clear
, NULL
);
This page took 0.058271 seconds and 4 git commands to generate.