#include "prop.h"
#include "extensions.h"
#include "frame.h"
+#include "session.h"
#include "event.h"
#include "grab.h"
#include "focus.h"
#include "openbox.h"
#include "group.h"
#include "config.h"
-#include "menu.h"
+#include "menuframe.h"
+#include "keyboard.h"
+#include "mouse.h"
#include "render/render.h"
#include <glib.h>
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_apply_startup_state(ObClient *self);
+static void client_restore_session_state(ObClient *self);
+static void client_restore_session_stacking(ObClient *self);
void client_startup()
{
/* create the ObClient struct, and populate it from the hints on the
window */
- self = g_new(ObClient, 1);
+ self = g_new0(ObClient, 1);
self->obwin.type = Window_Client;
self->window = window;
+
client_get_all(self);
+ client_restore_session_state(self);
+
+ client_change_state(self);
/* remove the client's border (and adjust re gravity) */
client_toggle_border(self, FALSE);
grab_server(FALSE);
- /* add to client list/map */
- client_list = g_list_append(client_list, self);
- g_hash_table_insert(window_map, &self->window, self);
-
/* update the focus lists */
focus_order_add_new(self);
stacking_add(CLIENT_AS_WINDOW(self));
+ client_restore_session_stacking(self);
/* focus the new window? */
if (ob_state() != OB_STATE_STARTING && config_focus_new &&
(self->type == OB_CLIENT_TYPE_NORMAL ||
self->type == OB_CLIENT_TYPE_DIALOG))
{
+ activate = TRUE;
+#if 0
if (self->desktop != screen_desktop) {
/* activate the window */
activate = TRUE;
activate = TRUE;
}
}
+#endif
}
dispatch_client(Event_Client_New, self, 0, 0);
/* make sure the window is visible */
- client_move_onscreen(self);
-
- screen_update_areas();
+ if (ob_state() == OB_STATE_RUNNING)
+ client_move_onscreen(self, client_normal(self));
client_showhide(self);
if (screen_showing_desktop)
screen_show_desktop(FALSE);
+ /* add to client list/map */
+ client_list = g_list_append(client_list, self);
+ g_hash_table_insert(window_map, &self->window, self);
+
+ /* this has to happen after we're in the client_list */
+ screen_update_areas();
+
/* update the list hints */
client_set_list();
+ keyboard_grab_for_client(self, TRUE);
+ mouse_grab_for_client(self, TRUE);
+
dispatch_client(Event_Client_Mapped, self, 0, 0);
ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
client_unmanage(client_list->data);
}
-/* called by client_unmanage() to close any menus referencing this client */
-void client_close_menus(gpointer key, gpointer value, gpointer self)
-{
- if (((ObMenu *)value)->client == (ObClient *)self)
- menu_hide((ObMenu *)value);
-}
-
void client_unmanage(ObClient *self)
{
guint j;
dispatch_client(Event_Client_Destroy, self, 0, 0);
g_assert(self != NULL);
+ keyboard_grab_for_client(self, FALSE);
+ mouse_grab_for_client(self, FALSE);
+
/* remove the window from our save set */
XChangeSaveSet(ob_display, self->window, SetModeDelete);
if (moveresize_client == self)
moveresize_end(TRUE);
- /* close any windows that are attached to this window */
- g_hash_table_foreach(menu_hash, client_close_menus, self);
-
+ /* menus can be associated with a client, so close any that are since
+ we are disappearing now */
+ menu_frame_hide_all_client(self);
if (focus_client == self) {
XEvent e;
if (ob_state() != OB_STATE_EXITING) {
/* these values should not be persisted across a window
unmapping/mapping */
- prop_erase(self->window, prop_atoms.net_wm_desktop);
- prop_erase(self->window, prop_atoms.net_wm_state);
+ PROP_ERASE(self->window, net_wm_desktop);
+ PROP_ERASE(self->window, net_wm_state);
+ PROP_ERASE(self->window, wm_state);
} else {
/* if we're left in an iconic state, the client wont be mapped. this is
bad, since we will no longer be managing the window on restart */
client_set_list();
}
-void client_move_onscreen(ObClient *self)
+static void client_restore_session_state(ObClient *self)
+{
+ GList *it;
+
+ if (!(it = session_state_find(self)))
+ return;
+
+ self->session = it->data;
+
+ RECT_SET(self->area, self->session->x, self->session->y,
+ self->session->w, self->session->h);
+ self->positioned = TRUE;
+ XResizeWindow(ob_display, self->window,
+ self->session->w, self->session->h);
+
+ self->desktop = (self->session->desktop == DESKTOP_ALL ?
+ self->session->desktop :
+ MIN(screen_num_desktops - 1, self->session->desktop));
+ PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
+
+ self->shaded = self->session->shaded;
+ self->iconic = self->session->iconic;
+ self->skip_pager = self->session->skip_pager;
+ self->skip_taskbar = self->session->skip_taskbar;
+ self->fullscreen = self->session->fullscreen;
+ self->above = self->session->above;
+ self->below = self->session->below;
+ self->max_horz = self->session->max_horz;
+ self->max_vert = self->session->max_vert;
+}
+
+static void client_restore_session_stacking(ObClient *self)
+{
+ GList *it;
+
+ if (!self->session) return;
+
+ it = g_list_find(session_saved_state, self->session);
+ for (it = g_list_previous(it); it; it = g_list_previous(it)) {
+ GList *cit;
+
+ for (cit = client_list; cit; cit = g_list_next(cit))
+ if (session_state_cmp(it->data, cit->data))
+ break;
+ if (cit) {
+ client_calc_layer(self);
+ stacking_below(CLIENT_AS_WINDOW(self),
+ CLIENT_AS_WINDOW(cit->data));
+ break;
+ }
+ }
+}
+
+void client_move_onscreen(ObClient *self, gboolean rude)
+{
+ int x = self->area.x;
+ int y = self->area.y;
+ if (client_find_onscreen(self, &x, &y,
+ self->frame->area.width,
+ self->frame->area.height, rude)) {
+ client_configure(self, OB_CORNER_TOPLEFT, x, y,
+ self->area.width, self->area.height,
+ TRUE, TRUE);
+ }
+}
+
+gboolean client_find_onscreen(ObClient *self, int *x, int *y, int w, int h,
+ gboolean rude)
{
Rect *a;
- int x = self->frame->area.x, y = self->frame->area.y;
+ int ox = *x, oy = *y;
+
+ frame_client_gravity(self->frame, x, y); /* get where the frame
+ would be */
/* XXX watch for xinerama dead areas */
+
a = screen_area(self->desktop);
- if (x >= a->x + a->width - 1)
- x = a->x + a->width - self->frame->area.width;
- if (y >= a->y + a->height - 1)
- y = a->y + a->height - self->frame->area.height;
- if (x + self->frame->area.width - 1 < a->x)
- x = a->x;
- if (y + self->frame->area.height - 1< a->y)
- y = a->y;
-
- frame_frame_gravity(self->frame, &x, &y); /* get where the client
- should be */
- client_configure(self, OB_CORNER_TOPLEFT, x, y,
- self->area.width, self->area.height,
- TRUE, TRUE);
+ if (!self->strut.right && *x >= a->x + a->width - 1)
+ *x = a->x + a->width - self->frame->area.width;
+ if (!self->strut.bottom && *y >= a->y + a->height - 1)
+ *y = a->y + a->height - self->frame->area.height;
+ if (!self->strut.left && *x + self->frame->area.width - 1 < a->x)
+ *x = a->x;
+ if (!self->strut.top && *y + self->frame->area.height - 1 < a->y)
+ *y = a->y;
+
+ if (rude) {
+ /* this is my MOZILLA BITCHSLAP. oh ya it fucking feels good.
+ Java can suck it too. */
+
+ /* dont let windows map/move into the strut unless they
+ are bigger than the available area */
+ if (w <= a->width) {
+ if (!self->strut.left && *x < a->x) *x = a->x;
+ if (!self->strut.right && *x + w > a->x + a->width)
+ *x = a->x + a->width - w;
+ }
+ if (h <= a->height) {
+ if (!self->strut.top && *y < a->y) *y = a->y;
+ if (!self->strut.bottom && *y + h > a->y + a->height)
+ *y = a->y + a->height - h;
+ }
+ }
+
+ frame_frame_gravity(self->frame, x, y); /* get where the client
+ should be */
+
+ return ox != *x || oy != *y;
}
static void client_toggle_border(ObClient *self, gboolean show)
static void client_get_all(ObClient *self)
{
- /* update EVERYTHING!! */
-
- self->ignore_unmaps = 0;
-
- /* defaults */
- self->frame = NULL;
- self->title = self->icon_title = NULL;
+ /* non-zero defaults */
self->title_count = 1;
- self->name = self->class = self->role = NULL;
self->wmstate = NormalState;
- self->transient = FALSE;
- self->transients = NULL;
- self->transient_for = NULL;
self->layer = -1;
- self->urgent = FALSE;
- self->positioned = FALSE;
self->decorate = TRUE;
- self->group = NULL;
- self->nicons = 0;
client_get_area(self);
client_update_transient_for(self);
client_update_class(self);
client_update_strut(self);
client_update_icons(self);
-
- client_change_state(self);
}
static void client_get_area(ObClient *self)
if (!trdesk)
/* defaults to the current desktop */
self->desktop = screen_desktop;
-
}
if (self->desktop != d) {
/* set the desktop hint, to make sure that it always exists */
/* get the hints from the window */
if (XGetWMNormalHints(ob_display, self->window, &size, &ret)) {
- self->positioned = !!(size.flags & (PPosition|USPosition));
+ self->positioned = !!(size.flags & (PPosition|USPosition));
if (size.flags & PWinGravity) {
self->gravity = size.win_gravity;
self->decorations &= ~OB_FRAME_DECOR_MAXIMIZE;
}
+ /* kill the handle on fully maxed windows */
+ if (self->max_vert && self->max_horz)
+ self->decorations &= ~OB_FRAME_DECOR_HANDLE;
+
/* finally, the user can have requested no decorations, which overrides
everything */
if (!self->decorate)
- self->decorations = 0;
+ self->decorations = OB_FRAME_DECOR_BORDER;
/* if we don't have a titlebar, then we cannot shade! */
if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
client_change_allowed_actions(self);
if (self->frame) {
- /* this makes sure that these windows appear on all desktops */
- if (self->type == OB_CLIENT_TYPE_DESKTOP &&
- self->desktop != DESKTOP_ALL)
- client_set_desktop(self, DESKTOP_ALL, FALSE);
-
- /* adjust the client's decorations, etc. */
- client_reconfigure(self);
+ /* adjust the client's decorations, etc. */
+ client_reconfigure(self);
} else {
/* this makes sure that these windows appear on all desktops */
if (self->type == OB_CLIENT_TYPE_DESKTOP &&
}
}
- /* the WM_HINTS can contain an icon */
- client_update_icons(self);
-
/* because the self->transient flag wont change from this call,
we don't need to update the window's type and such, only its
transient_for, and the transients lists of other windows in
client_update_transient_for(self);
}
+ /* the WM_HINTS can contain an icon */
+ client_update_icons(self);
+
XFree(hints);
}
{
guint num;
guint32 *data;
+ gboolean got = FALSE;
+ StrutPartial strut;
+
+ if (PROP_GETA32(self->window, net_wm_strut_partial, cardinal,
+ &data, &num)) {
+ if (num == 12) {
+ got = TRUE;
+ STRUT_PARTIAL_SET(strut,
+ data[0], data[2], data[1], data[3],
+ data[4], data[5], data[8], data[9],
+ data[6], data[7], data[10], data[11]);
+ }
+ g_free(data);
+ }
- if (!PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) {
- STRUT_SET(self->strut, 0, 0, 0, 0);
- } else {
- if (num == 4)
- STRUT_SET(self->strut, data[0], data[2], data[1], data[3]);
- else
- STRUT_SET(self->strut, 0, 0, 0, 0);
- g_free(data);
+ if (!got &&
+ PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) {
+ if (num == 4) {
+ got = TRUE;
+ STRUT_PARTIAL_SET(strut,
+ data[0], data[2], data[1], data[3],
+ 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ g_free(data);
}
- /* updating here is pointless while we're being mapped cuz we're not in
- the client list yet */
- if (self->frame)
- screen_update_areas();
+ if (!got)
+ STRUT_PARTIAL_SET(strut, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (!STRUT_EQUAL(strut, self->strut)) {
+ self->strut = strut;
+
+ /* updating here is pointless while we're being mapped cuz we're not in
+ the client list yet */
+ if (self->frame)
+ screen_update_areas();
+ }
}
void client_update_icons(ObClient *self)
*/
}
-void client_configure(ObClient *self, ObCorner anchor,
- int x, int y, int w, int h,
- gboolean user, gboolean final)
+void client_configure_full(ObClient *self, ObCorner anchor,
+ int x, int y, int w, int h,
+ gboolean user, gboolean final,
+ gboolean force_reply)
{
gboolean moved = FALSE, resized = FALSE;
+ guint fdecor = self->frame->decorations;
+ gboolean fhorz = self->frame->max_horz;
+
+ /* make the frame recalculate its dimentions n shit without changing
+ anything visible for real, this way the constraints below can work with
+ the updated frame dimensions. */
+ frame_adjust_area(self->frame, TRUE, TRUE, TRUE);
/* gets the frame's position */
frame_client_gravity(self->frame, &x, &y);
/* set the size and position if maximized */
if (self->max_horz) {
- x = a->x - self->frame->size.left;
- w = a->width;
+ x = a->x;
+ w = a->width - self->frame->size.left - self->frame->size.right;
}
if (self->max_vert) {
y = a->y;
if (!(w == self->area.width && h == self->area.height)) {
int basew, baseh, minw, minh;
+ int mw, mh, aw, ah;
/* base size is substituted with min size if not specified */
if (self->base_size.width || self->base_size.height) {
minh = self->base_size.height;
}
- if (user) {
- /* for interactive resizing. have to move half an increment in each
- direction. */
-
- /* how far we are towards the next size inc */
- int mw = (w - basew) % self->size_inc.width;
- int mh = (h - baseh) % self->size_inc.height;
- /* amount to add */
- int aw = self->size_inc.width / 2;
- int ah = self->size_inc.height / 2;
- /* don't let us move into a new size increment */
- if (mw + aw >= self->size_inc.width)
- aw = self->size_inc.width - mw - 1;
- if (mh + ah >= self->size_inc.height)
- ah = self->size_inc.height - mh - 1;
- w += aw;
- h += ah;
+ /* for interactive resizing. have to move half an increment in each
+ direction. */
+
+ /* how far we are towards the next size inc */
+ mw = (w - basew) % self->size_inc.width;
+ mh = (h - baseh) % self->size_inc.height;
+ /* amount to add */
+ aw = self->size_inc.width / 2;
+ ah = self->size_inc.height / 2;
+ /* don't let us move into a new size increment */
+ if (mw + aw >= self->size_inc.width)
+ aw = self->size_inc.width - mw - 1;
+ if (mh + ah >= self->size_inc.height)
+ ah = self->size_inc.height - mh - 1;
+ w += aw;
+ h += ah;
- /* if this is a user-requested resize, then check against min/max
- sizes */
-
- /* smaller than min size or bigger than max size? */
- if (w > self->max_size.width) w = self->max_size.width;
- if (w < minw) w = minw;
- if (h > self->max_size.height) h = self->max_size.height;
- if (h < minh) h = minh;
- }
+ /* if this is a user-requested resize, then check against min/max
+ sizes */
+
+ /* smaller than min size or bigger than max size? */
+ if (w > self->max_size.width) w = self->max_size.width;
+ if (w < minw) w = minw;
+ if (h > self->max_size.height) h = self->max_size.height;
+ if (h < minh) h = minh;
w -= basew;
h -= baseh;
h /= self->size_inc.height;
/* you cannot resize to nothing */
- if (w < 1) w = 1;
- if (h < 1) h = 1;
+ if (basew + w < 1) w = 1 - basew;
+ if (baseh + h < 1) h = 1 - baseh;
/* store the logical size */
- SIZE_SET(self->logical_size, w, h);
+ SIZE_SET(self->logical_size,
+ self->size_inc.width > 1 ? w : w + basew,
+ self->size_inc.height > 1 ? h : h + baseh);
w *= self->size_inc.width;
h *= self->size_inc.height;
w += basew;
h += baseh;
- if (user) {
- /* adjust the height to match the width for the aspect ratios.
- for this, min size is not substituted for base size ever. */
- w -= self->base_size.width;
- h -= self->base_size.height;
+ /* adjust the height to match the width for the aspect ratios.
+ for this, min size is not substituted for base size ever. */
+ w -= self->base_size.width;
+ h -= self->base_size.height;
- if (self->min_ratio)
- if (h * self->min_ratio > w) h = (int)(w / self->min_ratio);
- if (self->max_ratio)
- if (h * self->max_ratio < w) h = (int)(w / self->max_ratio);
+ if (self->min_ratio)
+ if (h * self->min_ratio > w) h = (int)(w / self->min_ratio);
+ if (self->max_ratio)
+ if (h * self->max_ratio < w) h = (int)(w / self->max_ratio);
- w += self->base_size.width;
- h += self->base_size.height;
- }
+ w += self->base_size.width;
+ h += self->base_size.height;
}
switch (anchor) {
/* for app-requested resizes, always resize if 'resized' is true.
for user-requested ones, only resize if final is true, or when
- resizing in opaque mode */
+ resizing in redraw mode */
if ((!user && resized) ||
- (user && (final || (resized && config_opaque_resize))))
+ (user && (final || (resized && config_redraw_resize))))
XResizeWindow(ob_display, self->window, w, h);
/* move/resize the frame to match the request */
if (self->frame) {
- if (self->decorations != self->frame->decorations)
+ if (self->decorations != fdecor || self->max_horz != fhorz)
moved = resized = TRUE;
if (moved || resized)
- frame_adjust_area(self->frame, moved, resized);
+ frame_adjust_area(self->frame, moved, resized, FALSE);
- /* If you send this and the client hasn't changed you end up with buggy
- clients (emacs) freaking out, cuz they send back a configure every
- time they receive this event, which resends them this event... etc.
- */
- if ((!user && moved) || (user && final)) {
+ if (!resized && (force_reply || ((!user && moved) || (user && final))))
+ {
XEvent event;
event.type = ConfigureNotify;
event.xconfigure.display = ob_display;
event.xconfigure.event = self->window;
event.xconfigure.window = self->window;
-
+
/* root window real coords */
- event.xconfigure.x = self->frame->area.x + self->frame->size.left;
- event.xconfigure.y = self->frame->area.y + self->frame->size.top;
-
+ event.xconfigure.x = self->frame->area.x + self->frame->size.left -
+ self->border_width;
+ event.xconfigure.y = self->frame->area.y + self->frame->size.top -
+ self->border_width;
event.xconfigure.width = w;
event.xconfigure.height = h;
event.xconfigure.border_width = 0;
client_change_state(self); /* change the state hints on the client */
+ client_setup_decor_and_functions(self);
+
/* figure out where the client should be going */
frame_frame_gravity(self->frame, &x, &y);
client_configure(self, OB_CORNER_TOPLEFT, x, y, w, h, TRUE, TRUE);
self->shaded = shade;
client_change_state(self);
/* resize the frame to just the titlebar */
- frame_adjust_area(self->frame, FALSE, FALSE);
+ frame_adjust_area(self->frame, FALSE, FALSE, FALSE);
}
void client_close(ObClient *self)
focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
}
-void client_activate(ObClient *self)
+void client_activate(ObClient *self, gboolean here)
{
if (client_normal(self) && screen_showing_desktop)
screen_show_desktop(FALSE);
if (self->iconic)
client_iconify(self, FALSE, FALSE);
if (self->desktop != DESKTOP_ALL &&
- self->desktop != screen_desktop)
- screen_set_desktop(self->desktop);
- else if (!self->frame->visible)
+ self->desktop != screen_desktop) {
+ if (here)
+ client_set_desktop(self, screen_desktop, FALSE);
+ else
+ screen_set_desktop(self->desktop);
+ } else if (!self->frame->visible)
/* if its not visible for other reasons, then don't mess
with it */
return;
his_cy = (cur->frame->area.y - my_cy)
+ cur->frame->area.height / 2;
- if(dir > 3) {
+ if(dir == OB_DIRECTION_NORTHEAST || dir == OB_DIRECTION_SOUTHEAST ||
+ dir == OB_DIRECTION_SOUTHWEST || dir == OB_DIRECTION_NORTHWEST) {
int tx;
/* Rotate the diagonals 45 degrees counterclockwise.
* To do this, multiply the matrix /+h +h\ with the
}
return NULL;
}
+
+gchar* client_get_sm_client_id(ObClient *self)
+{
+ gchar *id = NULL;
+
+ if (!PROP_GETS(self->window, sm_client_id, locale, &id) && self->group)
+ PROP_GETS(self->group->leader, sm_client_id, locale, &id);
+ return id;
+}
+
+/* finds the nearest edge in the given direction from the current client
+ * note to self: the edge is the -frame- edge (the actual one), not the
+ * client edge.
+ */
+int client_directional_edge_search(ObClient *c, ObDirection dir)
+{
+ int dest;
+ int my_edge_start, my_edge_end, my_offset;
+ GList *it;
+ Rect *a;
+
+ if(!client_list)
+ return -1;
+
+ a = screen_area(c->desktop);
+
+ switch(dir) {
+ case OB_DIRECTION_NORTH:
+ my_edge_start = c->frame->area.x;
+ my_edge_end = c->frame->area.x + c->frame->area.width;
+ my_offset = c->frame->area.y;
+
+ dest = a->y; /* default: top of screen */
+
+ for(it = g_list_first(client_list); it; it = it->next) {
+ int his_edge_start, his_edge_end, his_offset;
+ ObClient *cur = it->data;
+
+ if(cur == c)
+ continue;
+ if(!client_normal(cur))
+ continue;
+ if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ continue;
+ if(cur->iconic)
+ continue;
+
+ his_edge_start = cur->frame->area.x;
+ his_edge_end = cur->frame->area.x + cur->frame->area.width;
+ his_offset = cur->frame->area.y + cur->frame->area.height;
+
+ if(his_offset + 1 > my_offset)
+ continue;
+
+ if(his_offset < dest)
+ continue;
+
+ if(his_edge_start >= my_edge_start &&
+ his_edge_start <= my_edge_end)
+ dest = his_offset;
+
+ if(my_edge_start >= his_edge_start &&
+ my_edge_start <= his_edge_end)
+ dest = his_offset;
+
+ }
+ break;
+ case OB_DIRECTION_SOUTH:
+ my_edge_start = c->frame->area.x;
+ my_edge_end = c->frame->area.x + c->frame->area.width;
+ my_offset = c->frame->area.y + c->frame->area.height;
+
+ dest = a->y + a->height; /* default: bottom of screen */
+
+ for(it = g_list_first(client_list); it; it = it->next) {
+ int his_edge_start, his_edge_end, his_offset;
+ ObClient *cur = it->data;
+
+ if(cur == c)
+ continue;
+ if(!client_normal(cur))
+ continue;
+ if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ continue;
+ if(cur->iconic)
+ continue;
+
+ his_edge_start = cur->frame->area.x;
+ his_edge_end = cur->frame->area.x + cur->frame->area.width;
+ his_offset = cur->frame->area.y;
+
+
+ if(his_offset - 1 < my_offset)
+ continue;
+
+ if(his_offset > dest)
+ continue;
+
+ if(his_edge_start >= my_edge_start &&
+ his_edge_start <= my_edge_end)
+ dest = his_offset;
+
+ if(my_edge_start >= his_edge_start &&
+ my_edge_start <= his_edge_end)
+ dest = his_offset;
+
+ }
+ break;
+ case OB_DIRECTION_WEST:
+ my_edge_start = c->frame->area.y;
+ my_edge_end = c->frame->area.y + c->frame->area.height;
+ my_offset = c->frame->area.x;
+
+ dest = a->x; /* default: leftmost egde of screen */
+
+ for(it = g_list_first(client_list); it; it = it->next) {
+ int his_edge_start, his_edge_end, his_offset;
+ ObClient *cur = it->data;
+
+ if(cur == c)
+ continue;
+ if(!client_normal(cur))
+ continue;
+ if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ continue;
+ if(cur->iconic)
+ continue;
+
+ his_edge_start = cur->frame->area.y;
+ his_edge_end = cur->frame->area.y + cur->frame->area.height;
+ his_offset = cur->frame->area.x + cur->frame->area.width;
+
+ if(his_offset + 1 > my_offset)
+ continue;
+
+ if(his_offset < dest)
+ continue;
+
+ if(his_edge_start >= my_edge_start &&
+ his_edge_start <= my_edge_end)
+ dest = his_offset;
+
+ if(my_edge_start >= his_edge_start &&
+ my_edge_start <= his_edge_end)
+ dest = his_offset;
+
+
+ }
+ break;
+ case OB_DIRECTION_EAST:
+ my_edge_start = c->frame->area.y;
+ my_edge_end = c->frame->area.y + c->frame->area.height;
+ my_offset = c->frame->area.x + c->frame->area.width;
+
+ dest = a->x + a->width; /* default: rightmost edge of screen */
+
+ for(it = g_list_first(client_list); it; it = it->next) {
+ int his_edge_start, his_edge_end, his_offset;
+ ObClient *cur = it->data;
+
+ if(cur == c)
+ continue;
+ if(!client_normal(cur))
+ continue;
+ if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ continue;
+ if(cur->iconic)
+ continue;
+
+ his_edge_start = cur->frame->area.y;
+ his_edge_end = cur->frame->area.y + cur->frame->area.height;
+ his_offset = cur->frame->area.x;
+
+ if(his_offset - 1 < my_offset)
+ continue;
+
+ if(his_offset > dest)
+ continue;
+
+ if(his_edge_start >= my_edge_start &&
+ his_edge_start <= my_edge_end)
+ dest = his_offset;
+
+ if(my_edge_start >= his_edge_start &&
+ my_edge_start <= his_edge_end)
+ dest = his_offset;
+
+ }
+ break;
+ case OB_DIRECTION_NORTHEAST:
+ case OB_DIRECTION_SOUTHEAST:
+ case OB_DIRECTION_NORTHWEST:
+ case OB_DIRECTION_SOUTHWEST:
+ /* not implemented */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return dest;
+}