]>
Dogcows Code - chaz/openbox/blob - plugins/mouse/mouse.c
1 #include "../../kernel/openbox.h"
2 #include "../../kernel/dispatch.h"
3 #include "../../kernel/action.h"
4 #include "../../kernel/event.h"
5 #include "../../kernel/client.h"
6 #include "../../kernel/frame.h"
7 #include "../../kernel/grab.h"
8 #include "../../kernel/engine.h"
11 #include "mouserc_parse.h"
14 void plugin_setup_config()
18 static int drag_threshold
= 3;
20 /* GData of GSList*s of PointerBinding*s. */
21 static GData
*bound_contexts
;
23 struct foreach_grab_temp
{
28 static void foreach_grab(GQuark key
, gpointer data
, gpointer user_data
)
30 struct foreach_grab_temp
*d
= user_data
;
32 for (it
= data
; it
!= NULL
; it
= it
->next
) {
33 /* grab/ungrab the button */
34 MouseBinding
*b
= it
->data
;
39 if (key
== g_quark_try_string("frame")) {
40 win
= d
->client
->frame
->window
;
42 mask
= ButtonPressMask
| ButtonMotionMask
| ButtonReleaseMask
;
43 } else if (key
== g_quark_try_string("client")) {
44 win
= d
->client
->frame
->plate
;
45 mode
= GrabModeSync
; /* this is handled in event */
46 mask
= ButtonPressMask
; /* can't catch more than this with Sync
47 mode the release event is manufactured
52 grab_button(b
->button
, b
->state
, win
, mask
, mode
);
54 ungrab_button(b
->button
, b
->state
, win
);
58 static void grab_for_client(Client
*client
, gboolean grab
)
60 struct foreach_grab_temp bt
;
63 g_datalist_foreach(&bound_contexts
, foreach_grab
, &bt
);
66 static void grab_all_clients(gboolean grab
)
70 for (it
= client_list
; it
!= NULL
; it
= it
->next
)
71 grab_for_client(it
->data
, grab
);
74 static void foreach_clear(GQuark key
, gpointer data
, gpointer user_data
)
77 user_data
= user_data
;
78 for (it
= data
; it
!= NULL
; it
= it
->next
) {
81 MouseBinding
*b
= it
->data
;
82 for (i
= 0; i
< NUM_MOUSEACTION
; ++i
)
83 if (b
->action
[i
] != NULL
)
84 action_free(b
->action
[i
]);
90 static void fire_button(MouseAction a
, GQuark context
, Client
*c
, guint state
,
96 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
97 it
!= NULL
; it
= it
->next
) {
99 if (b
->state
== state
&& b
->button
== button
)
102 /* if not bound, then nothing to do! */
103 if (it
== NULL
) return;
105 if (b
->action
[a
] != NULL
&& b
->action
[a
]->func
!= NULL
) {
106 b
->action
[a
]->data
.any
.c
= c
;
108 g_assert(!(b
->action
[a
]->func
== action_move
||
109 b
->action
[a
]->func
== action_resize
));
111 b
->action
[a
]->func(&b
->action
[a
]->data
);
115 /* corner should be the opposite corner of the window in which the pointer
116 clicked, Corner_TopLeft if a good default if there is no client
117 Returns True or False for if a binding existed for the action or not.
119 static gboolean
fire_motion(MouseAction a
, GQuark context
, Client
*c
,
120 guint state
, guint button
, int cx
, int cy
,
121 int cw
, int ch
, int dx
, int dy
,
122 gboolean final
, Corner corner
)
127 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
128 it
!= NULL
; it
= it
->next
) {
130 if (b
->state
== state
&& b
->button
== button
)
133 /* if not bound, then nothing to do! */
134 if (it
== NULL
) return FALSE
;
136 if (b
->action
[a
] != NULL
&& b
->action
[a
]->func
!= NULL
) {
137 b
->action
[a
]->data
.any
.c
= c
;
139 if (b
->action
[a
]->func
== action_move
) {
140 b
->action
[a
]->data
.move
.x
= cx
+ dx
;
141 b
->action
[a
]->data
.move
.y
= cy
+ dy
;
142 b
->action
[a
]->data
.move
.final
= final
;
143 } else if (b
->action
[a
]->func
== action_resize
) {
144 b
->action
[a
]->data
.resize
.corner
= corner
;
147 b
->action
[a
]->data
.resize
.x
= cw
+ dx
;
148 b
->action
[a
]->data
.resize
.y
= ch
+ dy
;
150 case Corner_TopRight
:
151 b
->action
[a
]->data
.resize
.x
= cw
- dx
;
152 b
->action
[a
]->data
.resize
.y
= ch
+ dy
;
154 case Corner_BottomLeft
:
155 b
->action
[a
]->data
.resize
.x
= cw
+ dx
;
156 b
->action
[a
]->data
.resize
.y
= ch
- dy
;
158 case Corner_BottomRight
:
159 b
->action
[a
]->data
.resize
.x
= cw
- dx
;
160 b
->action
[a
]->data
.resize
.y
= ch
- dy
;
163 b
->action
[a
]->data
.resize
.final
= final
;
165 b
->action
[a
]->func(&b
->action
[a
]->data
);
171 static Corner
pick_corner(int x
, int y
, int cx
, int cy
, int cw
, int ch
)
173 if (x
- cx
< cw
/ 2) {
175 return Corner_BottomRight
;
177 return Corner_TopRight
;
180 return Corner_BottomLeft
;
182 return Corner_TopLeft
;
186 static void event(ObEvent
*e
, void *foo
)
189 static int px
, py
, cx
, cy
, cw
, ch
, dx
, dy
;
190 static guint button
= 0, lbutton
= 0;
191 static gboolean drag
= FALSE
, drag_used
= FALSE
;
192 static Corner corner
= Corner_TopLeft
;
193 gboolean click
= FALSE
;
194 gboolean dclick
= FALSE
;
198 case Event_Client_Mapped
:
199 grab_for_client(e
->data
.c
.client
, TRUE
);
202 case Event_Client_Destroy
:
203 grab_for_client(e
->data
.c
.client
, FALSE
);
206 case Event_X_ButtonPress
:
208 if (e
->data
.x
.client
!= NULL
) {
209 cx
= e
->data
.x
.client
->frame
->area
.x
;
210 cy
= e
->data
.x
.client
->frame
->area
.y
;
211 /* use the client size because the frame can be differently
212 sized (shaded windows) and we want this based on the clients
214 cw
= e
->data
.x
.client
->area
.width
+
215 e
->data
.x
.client
->frame
->size
.left
+
216 e
->data
.x
.client
->frame
->size
.right
;
217 ch
= e
->data
.x
.client
->area
.height
+
218 e
->data
.x
.client
->frame
->size
.top
+
219 e
->data
.x
.client
->frame
->size
.bottom
;
220 px
= e
->data
.x
.e
->xbutton
.x_root
;
221 py
= e
->data
.x
.e
->xbutton
.y_root
;
222 corner
= pick_corner(px
, py
, cx
, cy
, cw
, ch
);
224 button
= e
->data
.x
.e
->xbutton
.button
;
226 context
= engine_get_context(e
->data
.x
.client
,
227 e
->data
.x
.e
->xbutton
.window
);
229 fire_button(MouseAction_Press
, context
,
230 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
231 e
->data
.x
.e
->xbutton
.button
);
233 if (context
== g_quark_try_string("client")) {
234 /* Replay the event, so it goes to the client*/
235 XAllowEvents(ob_display
, ReplayPointer
, event_lasttime
);
236 /* Fall through to the release case! */
240 case Event_X_ButtonRelease
:
241 context
= engine_get_context(e
->data
.x
.client
,
242 e
->data
.x
.e
->xbutton
.window
);
243 if (e
->data
.x
.e
->xbutton
.button
== button
) {
246 fire_motion(MouseAction_Motion
, context
,
247 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
248 e
->data
.x
.e
->xbutton
.button
,
249 cx
, cy
, cw
, ch
, dx
, dy
, TRUE
, corner
);
250 drag
= drag_used
= FALSE
;
254 /* clicks are only valid if its released over the window */
257 guint ujunk
, b
, w
, h
;
258 XGetGeometry(ob_display
, e
->data
.x
.e
->xbutton
.window
,
259 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
260 if (e
->data
.x
.e
->xbutton
.x
>= (signed)-b
&&
261 e
->data
.x
.e
->xbutton
.y
>= (signed)-b
&&
262 e
->data
.x
.e
->xbutton
.x
< (signed)(w
+b
) &&
263 e
->data
.x
.e
->xbutton
.y
< (signed)(h
+b
)) {
265 /* double clicks happen if there were 2 in a row! */
266 if (lbutton
== button
&&
267 e
->data
.x
.e
->xbutton
.time
- 300 <= ltime
) {
277 ltime
= e
->data
.x
.e
->xbutton
.time
;
279 fire_button(MouseAction_Release
, context
,
280 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
281 e
->data
.x
.e
->xbutton
.button
);
283 fire_button(MouseAction_Click
, context
,
284 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
285 e
->data
.x
.e
->xbutton
.button
);
287 fire_button(MouseAction_DClick
, context
,
288 e
->data
.x
.client
, e
->data
.x
.e
->xbutton
.state
,
289 e
->data
.x
.e
->xbutton
.button
);
292 case Event_X_MotionNotify
:
294 dx
= e
->data
.x
.e
->xmotion
.x_root
- px
;
295 dy
= e
->data
.x
.e
->xmotion
.y_root
- py
;
297 (ABS(dx
) >= drag_threshold
|| ABS(dy
) >= drag_threshold
))
300 context
= engine_get_context(e
->data
.x
.client
,
301 e
->data
.x
.e
->xbutton
.window
);
302 drag_used
= fire_motion(MouseAction_Motion
, context
,
304 e
->data
.x
.e
->xmotion
.state
,
305 button
, cx
, cy
, cw
, ch
, dx
, dy
,
312 g_assert_not_reached();
316 gboolean
mbind(char *buttonstr
, char *contextstr
, MouseAction mact
,
324 if (!translate_button(buttonstr
, &state
, &button
)) {
325 g_warning("invalid button '%s'", buttonstr
);
329 contextstr
= g_ascii_strdown(contextstr
, -1);
330 context
= g_quark_try_string(contextstr
);
332 g_warning("invalid context '%s'", contextstr
);
338 for (it
= g_datalist_id_get_data(&bound_contexts
, context
);
339 it
!= NULL
; it
= it
->next
){
341 if (b
->state
== state
&& b
->button
== button
) {
343 if (b
->action
[mact
] != NULL
) {
344 g_warning("duplicate binding");
347 b
->action
[mact
] = action
;
352 grab_all_clients(FALSE
);
354 /* add the binding */
355 b
= g_new0(MouseBinding
, 1);
358 b
->action
[mact
] = action
;
359 g_datalist_id_set_data(&bound_contexts
, context
,
360 g_slist_append(g_datalist_id_get_data(&bound_contexts
, context
), b
));
362 grab_all_clients(TRUE
);
367 void plugin_startup()
369 dispatch_register(Event_Client_Mapped
| Event_Client_Destroy
|
370 Event_X_ButtonPress
| Event_X_ButtonRelease
|
371 Event_X_MotionNotify
, (EventHandler
)event
, NULL
);
376 void plugin_shutdown()
378 dispatch_register(0, (EventHandler
)event
, NULL
);
380 grab_all_clients(FALSE
);
381 g_datalist_foreach(&bound_contexts
, foreach_clear
, NULL
);
This page took 0.049401 seconds and 4 git commands to generate.