2 * mouse.c - mouse managing
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "layouts/floating.h"
31 #include "layouts/tile.h"
32 #include "common/xscreen.h"
34 #define MOUSEMASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
36 extern AwesomeConf globalconf
;
39 mouse_snapclienttogeometry_outside(area_t geometry
, area_t snap_geometry
, int snap
)
41 if(geometry
.x
< snap
+ snap_geometry
.x
+ snap_geometry
.width
42 && geometry
.x
> snap_geometry
.x
+ snap_geometry
.width
)
43 geometry
.x
= snap_geometry
.x
+ snap_geometry
.width
;
44 else if(geometry
.x
+ geometry
.width
< snap_geometry
.x
45 && geometry
.x
+ geometry
.width
> snap_geometry
.x
- snap
)
46 geometry
.x
= snap_geometry
.x
- geometry
.width
;
49 if(geometry
.y
< snap
+ snap_geometry
.y
+ snap_geometry
.height
50 && geometry
.y
> snap_geometry
.y
+ snap_geometry
.height
)
51 geometry
.y
= snap_geometry
.y
+ snap_geometry
.height
;
52 else if(geometry
.y
+ geometry
.height
< snap_geometry
.y
53 && geometry
.y
+ geometry
.height
> snap_geometry
.y
- snap
)
54 geometry
.y
= snap_geometry
.y
- geometry
.height
;
60 mouse_snapclienttogeometry_inside(area_t geometry
, area_t snap_geometry
, int snap
)
62 if(abs(geometry
.x
) < snap
+ snap_geometry
.x
&& geometry
.x
> snap_geometry
.x
)
63 geometry
.x
= snap_geometry
.x
;
64 else if(abs((snap_geometry
.x
+ snap_geometry
.width
) - (geometry
.x
+ geometry
.width
))
66 geometry
.x
= snap_geometry
.x
+ snap_geometry
.width
- geometry
.width
;
67 if(abs(geometry
.y
) < snap
+ snap_geometry
.y
&& geometry
.y
> snap_geometry
.y
)
68 geometry
.y
= snap_geometry
.y
;
69 else if(abs((snap_geometry
.y
+ snap_geometry
.height
) - (geometry
.y
+ geometry
.height
))
71 geometry
.y
= snap_geometry
.y
+ snap_geometry
.height
- geometry
.height
;
77 mouse_snapclient(Client
*c
, area_t geometry
)
80 int snap
= globalconf
.screens
[c
->screen
].snap
;
81 area_t snapper_geometry
;
82 area_t screen_geometry
=
83 screen_get_area(c
->screen
,
84 globalconf
.screens
[c
->screen
].statusbar
,
85 &globalconf
.screens
[c
->screen
].padding
);
87 geometry
= titlebar_geometry_add(&c
->titlebar
, geometry
);
88 geometry
.width
+= 2 * c
->border
;
89 geometry
.height
+= 2 * c
->border
;
92 mouse_snapclienttogeometry_inside(geometry
, screen_geometry
, snap
);
94 for(snapper
= globalconf
.clients
; snapper
; snapper
= snapper
->next
)
95 if(snapper
!= c
&& client_isvisible(c
, c
->screen
))
97 snapper_geometry
= snapper
->geometry
;
98 snapper_geometry
.width
+= 2 * c
->border
;
99 snapper_geometry
.height
+= 2 * c
->border
;
100 snapper_geometry
= titlebar_geometry_add(&snapper
->titlebar
,
103 mouse_snapclienttogeometry_outside(geometry
,
108 geometry
.width
-= 2 * c
->border
;
109 geometry
.height
-= 2 * c
->border
;
110 return titlebar_geometry_remove(&c
->titlebar
, geometry
);
114 mouse_resizebar_draw(DrawCtx
*ctx
, style_t style
, SimpleWindow
*sw
, area_t geometry
, int border
)
116 area_t draw_geometry
= { 0, 0, ctx
->width
, ctx
->height
, NULL
, NULL
};
119 snprintf(size
, sizeof(size
), "%dx%d+%d+%d",
120 geometry
.x
, geometry
.y
, geometry
.width
, geometry
.height
);
121 draw_text(ctx
, draw_geometry
, AlignCenter
, style
.font
->height
/ 2, size
, style
);
122 simplewindow_move(sw
,
123 geometry
.x
+ ((2 * border
+ geometry
.width
) - sw
->geometry
.width
) / 2,
124 geometry
.y
+ ((2 * border
+ geometry
.height
) - sw
->geometry
.height
) / 2);
125 simplewindow_refresh_drawable(sw
, sw
->phys_screen
);
128 /** Move the focused window with the mouse.
129 * \param screen Screen ID
131 * \ingroup ui_callback
134 uicb_client_movemouse(int screen
, char *arg
__attribute__ ((unused
)))
136 int x
, y
, ocx
, ocy
, di
, newscreen
;
141 Client
*c
= globalconf
.focus
->client
, *target
;
142 Layout
*layout
= layout_get_current(screen
);
143 SimpleWindow
*sw
= NULL
;
148 || XGrabPointer(globalconf
.display
,
149 RootWindow(globalconf
.display
, c
->phys_screen
),
150 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
151 RootWindow(globalconf
.display
, c
->phys_screen
),
152 globalconf
.cursor
[CurMove
], CurrentTime
) != GrabSuccess
)
155 XQueryPointer(globalconf
.display
,
156 RootWindow(globalconf
.display
, c
->phys_screen
),
157 &dummy
, &dummy
, &x
, &y
, &di
, &di
, &dui
);
159 geometry
= c
->geometry
;
164 style
= globalconf
.screens
[c
->screen
].styles
.focus
;
166 if(c
->isfloating
|| layout
->arrange
== layout_floating
)
168 sw
= simplewindow_new(globalconf
.display
, c
->phys_screen
, 0, 0,
169 draw_textwidth(globalconf
.display
,
170 globalconf
.screens
[c
->screen
].styles
.focus
.font
,
171 "0000x0000+0000+0000") + style
.font
->height
,
172 1.5 * style
.font
->height
, 0);
174 ctx
= draw_context_new(globalconf
.display
, sw
->phys_screen
,
175 sw
->geometry
.width
, sw
->geometry
.height
,
177 XMapRaised(globalconf
.display
, sw
->window
);
178 mouse_resizebar_draw(ctx
, style
, sw
, geometry
, c
->border
);
183 XMaskEvent(globalconf
.display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
187 XUngrabPointer(globalconf
.display
, CurrentTime
);
190 draw_context_delete(&ctx
);
191 simplewindow_delete(&sw
);
194 case ConfigureRequest
:
195 event_handle_configurerequest(&ev
);
198 event_handle_expose(&ev
);
201 event_handle_maprequest(&ev
);
204 event_handle_enternotify(&ev
);
207 if(c
->isfloating
|| layout
->arrange
== layout_floating
)
209 geometry
.x
= ocx
+ (ev
.xmotion
.x
- x
);
210 geometry
.y
= ocy
+ (ev
.xmotion
.y
- y
);
212 geometry
= mouse_snapclient(c
, geometry
);
215 client_resize(c
, geometry
, False
);
218 mouse_resizebar_draw(ctx
, style
, sw
, c
->geometry
, c
->border
);
222 XQueryPointer(globalconf
.display
,
223 RootWindow(globalconf
.display
, c
->phys_screen
),
224 &dummy
, &child
, &x
, &y
, &di
, &di
, &dui
);
225 if((newscreen
= screen_get_bycoord(globalconf
.screens_info
, c
->screen
, x
, y
)) != c
->screen
)
227 move_client_to_screen(c
, newscreen
, True
);
228 globalconf
.screens
[c
->screen
].need_arrange
= True
;
229 if(layout_get_current(newscreen
)->arrange
!= layout_floating
)
230 globalconf
.screens
[newscreen
].need_arrange
= True
;
233 if((target
= client_get_bywin(globalconf
.clients
, child
))
234 && target
!= c
&& !target
->isfloating
)
236 client_list_swap(&globalconf
.clients
, c
, target
);
237 globalconf
.screens
[c
->screen
].need_arrange
= True
;
241 while(XCheckMaskEvent(globalconf
.display
, PointerMotionMask
, &ev
));
247 /** Resize the focused window with the mouse.
248 * \param screen Screen ID
250 * \ingroup ui_callback
253 uicb_client_resizemouse(int screen
, char *arg
__attribute__ ((unused
)))
255 int ocx
= 0, ocy
= 0, n
;
257 Client
*c
= globalconf
.focus
->client
;
258 Tag
**curtags
= tags_get_current(screen
);
259 Layout
*layout
= curtags
[0]->layout
;
260 area_t area
= { 0, 0, 0, 0, NULL
, NULL
}, geometry
= { 0, 0, 0, 0, NULL
, NULL
};
262 SimpleWindow
*sw
= NULL
;
266 /* only handle floating and tiled layouts */
270 style
= globalconf
.screens
[c
->screen
].styles
.focus
;
272 if(layout
->arrange
== layout_floating
|| c
->isfloating
)
278 sw
= simplewindow_new(globalconf
.display
, c
->phys_screen
, 0, 0,
279 draw_textwidth(globalconf
.display
,
280 globalconf
.screens
[c
->screen
].styles
.focus
.font
,
281 "0000x0000+0000+0000") + style
.font
->height
,
282 1.5 * style
.font
->height
, 0);
284 ctx
= draw_context_new(globalconf
.display
, sw
->phys_screen
,
285 sw
->geometry
.width
, sw
->geometry
.height
,
287 XMapRaised(globalconf
.display
, sw
->window
);
288 mouse_resizebar_draw(ctx
, style
, sw
, c
->geometry
, c
->border
);
290 else if (layout
->arrange
== layout_tile
|| layout
->arrange
== layout_tileleft
291 || layout
->arrange
== layout_tilebottom
|| layout
->arrange
== layout_tiletop
)
293 for(n
= 0, c
= globalconf
.clients
; c
; c
= c
->next
)
294 if(IS_TILED(c
, screen
))
297 if(n
<= curtags
[0]->nmaster
) return;
299 for(c
= globalconf
.clients
; c
&& !IS_TILED(c
, screen
); c
= c
->next
);
302 area
= screen_get_area(screen
,
303 globalconf
.screens
[c
->screen
].statusbar
,
304 &globalconf
.screens
[c
->screen
].padding
);
309 if(XGrabPointer(globalconf
.display
,
310 RootWindow(globalconf
.display
, c
->phys_screen
),
311 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
312 RootWindow(globalconf
.display
, c
->phys_screen
),
313 globalconf
.cursor
[CurResize
], CurrentTime
) != GrabSuccess
)
316 if(curtags
[0]->layout
->arrange
== layout_tileleft
)
317 XWarpPointer(globalconf
.display
, None
, c
->win
, 0, 0, 0, 0, 0,
318 c
->geometry
.height
+ c
->border
- 1);
319 else if(curtags
[0]->layout
->arrange
== layout_tilebottom
)
320 XWarpPointer(globalconf
.display
, None
, c
->win
, 0, 0, 0, 0,
321 c
->geometry
.width
+ c
->border
- 1, c
->geometry
.height
+ c
->border
- 1);
322 else if(curtags
[0]->layout
->arrange
== layout_tiletop
)
323 XWarpPointer(globalconf
.display
, None
, c
->win
, 0, 0, 0, 0,
324 c
->geometry
.width
+ c
->border
- 1, 0);
326 XWarpPointer(globalconf
.display
, None
, c
->win
, 0, 0, 0, 0,
327 c
->geometry
.width
+ c
->border
- 1, c
->geometry
.height
+ c
->border
- 1);
331 XMaskEvent(globalconf
.display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
335 XUngrabPointer(globalconf
.display
, CurrentTime
);
338 draw_context_delete(&ctx
);
339 simplewindow_delete(&sw
);
342 case ConfigureRequest
:
343 event_handle_configurerequest(&ev
);
346 event_handle_expose(&ev
);
349 event_handle_maprequest(&ev
);
352 if(layout
->arrange
== layout_floating
|| c
->isfloating
)
354 if((geometry
.width
= ev
.xmotion
.x
- ocx
- 2 * c
->border
+ 1) <= 0)
356 if((geometry
.height
= ev
.xmotion
.y
- ocy
- 2 * c
->border
+ 1) <= 0)
358 geometry
.x
= c
->geometry
.x
;
359 geometry
.y
= c
->geometry
.y
;
360 client_resize(c
, geometry
, True
);
362 mouse_resizebar_draw(ctx
, style
, sw
, c
->geometry
, c
->border
);
364 else if(layout
->arrange
== layout_tile
|| layout
->arrange
== layout_tileleft
365 || layout
->arrange
== layout_tiletop
|| layout
->arrange
== layout_tilebottom
)
367 if(layout
->arrange
== layout_tile
)
368 mwfact
= (double) (ev
.xmotion
.x
- area
.x
) / area
.width
;
369 else if(curtags
[0]->layout
->arrange
== layout_tileleft
)
370 mwfact
= 1 - (double) (ev
.xmotion
.x
- area
.x
) / area
.width
;
371 else if(curtags
[0]->layout
->arrange
== layout_tilebottom
)
372 mwfact
= (double) (ev
.xmotion
.y
- area
.y
) / area
.height
;
374 mwfact
= 1 - (double) (ev
.xmotion
.y
- area
.y
) / area
.height
;
375 mwfact
= MAX(globalconf
.screens
[screen
].mwfact_lower_limit
,
376 MIN(globalconf
.screens
[screen
].mwfact_upper_limit
, mwfact
));
377 if(fabs(curtags
[0]->mwfact
- mwfact
) >= 0.01)
379 curtags
[0]->mwfact
= mwfact
;
380 globalconf
.screens
[screen
].need_arrange
= True
;
382 while(XCheckMaskEvent(globalconf
.display
, PointerMotionMask
, &ev
));
392 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80