Index: openbox/client.c =================================================================== RCS file: /cvs/cvsroot/openbox/openbox/client.c,v retrieving revision 1.322 diff -u -r1.322 client.c --- openbox/client.c 21 Mar 2004 20:02:47 -0000 1.322 +++ openbox/client.c 25 Mar 2004 00:55:05 -0000 @@ -356,9 +356,13 @@ if (x != ox || y != oy) client_move(self, x, y); - } - client_showhide(self); + /* As far as I can tell, clients that go through the other placement + functions don't get placed on the divide, so we only need to + do this if the client thinks it knows better*/ + client_move_onmonitor(self); + } + client_showhide(self); /* use client_focus instead of client_activate cuz client_activate does stuff like switch desktops etc and I'm not interested in all that when @@ -646,6 +650,62 @@ frame_frame_gravity(self->frame, x, y); /* get where the client should be */ + return ox != *x || oy != *y; +} + +void client_move_onmonitor (ObClient *self) +{ + gint x = self->area.x; + gint y = self->area.y; + if (screen_num_monitors > 1 && + client_find_onmonitor(self, &x, &y, + self->frame->area.width, + self->frame->area.height)) { + client_move(self, x, y); + } +} + +gboolean client_find_onmonitor(ObClient *self, gint *x, gint *y, gint w, gint h) +{ + Rect *a; + Size s; + gint ox = *x, oy = *y; + + if (! screen_num_monitors > 1 ) + return FALSE; + + frame_client_gravity(self->frame, x, y); /* get where the frame + would be */ + + a = screen_physical_area_monitor(client_monitor(self)); + + /* Get the difference between monitor size and client size + We use this to not place the client right on the edge + of the monitor as that looks lame. This way we place it + 10% of the difference of the client and monitor sizes away + from the monitor edge.*/ + RECT_DIFF(s, *a, self->area); + + /* only move clients onto a monitor if they are not wider than + the monitor itself. If they are wider, then there's really + not a lot we can do about them being placed on the monitor + divide*/ + if (w <= a->width) { + if (*x < a->x) + *x = a->x + (s.width * 0.1); + if (*x + w > a->x + a->width) + *x = a->x + a->width - w - (s.width * 0.1); + } + /* and for all you freaks who stack your monitors vertically */ + if (h <= a->height) { + if (*y < a->y) + *y = a->y + (s.height * 0.1); + if (*y + h > a->y + a->height) + *y = a->y + a->height - h - (s.height * 0.1); + } + + frame_frame_gravity(self->frame, x, y); /* get where the self + should be */ return ox != *x || oy != *y; } @@ -2990,6 +3050,9 @@ } } +/* Determines which physical monitor a client is on by calculating the + area of the part of the client on each monitor. The number of the + monitor containing the greatest area of the client is returned.*/ guint client_monitor(ObClient *self) { guint i; @@ -3116,15 +3179,16 @@ */ gint client_directional_edge_search(ObClient *c, ObDirection dir) { - gint dest; + gint dest, monitor_dest; gint my_edge_start, my_edge_end, my_offset; GList *it; - Rect *a; + Rect *a, *monitor; if(!client_list) return -1; a = screen_area(c->desktop); + monitor = screen_area_monitor(c->desktop, client_monitor(c)); switch(dir) { case OB_DIRECTION_NORTH: @@ -3134,8 +3198,13 @@ /* default: top of screen */ dest = a->y; + monitor_dest = monitor->y; + /* if the monitor edge comes before the screen edge, */ + /* use that as the destination instead. (For xinerama) */ + if (monitor_dest != dest && my_offset > monitor_dest) + dest = monitor_dest; - for(it = client_list; it; it = g_list_next(it)) { + for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; @@ -3175,8 +3244,13 @@ /* default: bottom of screen */ dest = a->y + a->height; + monitor_dest = monitor->y + monitor->height; + /* if the monitor edge comes before the screen edge, */ + /* use that as the destination instead. (For xinerama) */ + if (monitor_dest != dest && my_offset < monitor_dest) + dest = monitor_dest; - for(it = client_list; it; it = g_list_next(it)) { + for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; @@ -3217,8 +3291,13 @@ /* default: leftmost egde of screen */ dest = a->x; + monitor_dest = monitor->x; + /* if the monitor edge comes before the screen edge, */ + /* use that as the destination instead. (For xinerama) */ + if (monitor_dest != dest && my_offset > monitor_dest) + dest = monitor_dest; - for(it = client_list; it; it = g_list_next(it)) { + for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; @@ -3259,8 +3338,13 @@ /* default: rightmost edge of screen */ dest = a->x + a->width; + monitor_dest = monitor->x + monitor->width; + /* if the monitor edge comes before the screen edge, */ + /* use that as the destination instead. (For xinerama) */ + if (monitor_dest != dest && my_offset < monitor_dest) + dest = monitor_dest; - for(it = client_list; it; it = g_list_next(it)) { + for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; Index: openbox/client.h =================================================================== RCS file: /cvs/cvsroot/openbox/openbox/client.h,v retrieving revision 1.79 diff -u -r1.79 client.h --- openbox/client.h 21 Mar 2004 01:03:00 -0000 1.79 +++ openbox/client.h 25 Mar 2004 00:55:05 -0000 @@ -362,6 +362,23 @@ */ void client_move_onscreen(ObClient *self, gboolean rude); +/*! Finds coordinates to keep a client on one xinerama monitor. + @param self The client + @param x The x coord of the client, may be changed. + @param y The y coord of the client, may be changed. + @param w The width of the client. + @param w The height of the client. + @return true if the client was moved to be on-monitor; false if not. +*/ +gboolean client_find_onmonitor(ObClient *self, gint *x, gint *y, gint w, gint h); + + +/*! Moves a client so that it is on one monitor if it is straddling the monitor + divide in xinerama + @param self The client to move +*/ +void client_move_onmonitor(ObClient *self); + /*! Fullscreen's or unfullscreen's the client window @param fs true if the window should be made fullscreen; false if it should be returned to normal state. Index: openbox/geom.h =================================================================== RCS file: /cvs/cvsroot/openbox/openbox/geom.h,v retrieving revision 1.16 diff -u -r1.16 geom.h --- openbox/geom.h 21 Mar 2004 01:03:00 -0000 1.16 +++ openbox/geom.h 25 Mar 2004 00:55:05 -0000 @@ -40,6 +40,10 @@ int height; } Rect; +/* defines sz as the differences of the height and width of r and o */ +#define RECT_DIFF(sz, r, o) ((sz).width = (r).width - (o).width, \ + (sz).height = (r).height - (o).height) + #define RECT_LEFT(r) ((r).x) #define RECT_TOP(r) ((r).y) #define RECT_RIGHT(r) ((r).x + (r).width - 1) @@ -62,10 +66,13 @@ #define RECT_CONTAINS_RECT(r, o) \ ((o).x >= (r).x && (o).x + (o).width <= (r).x + (r).width && \ (o).y >= (r).y && (o).y + (o).height <= (r).y + (r).height) + +/* Returns true if Rect r and o intersect */ #define RECT_INTERSECTS_RECT(r, o) \ ((o).x < (r).x + (r).width && (o).x + (o).width > (r).x && \ (o).y < (r).y + (r).height && (o).y + (o).height > (r).y) +/* Sets Rect r to be the intersection of Rect a and b. */ #define RECT_SET_INTERSECTION(r, a, b) \ ((r).x = MAX((a).x, (b).x), \ (r).y = MAX((a).y, (b).y), \