Big changes to placement across multiple monitors.
Add a Primary option for which monitor to place new windows on. Make "Active" the default instead of "Any", which is just totally crazy. When a window is being placed in the FOREGROUND, use a monitor chosen in the following order: 1. same monitor as parent 2. primary monitor if placement=PRIMARY active monitor if placement=ACTIVE pointer monitor if placement=MOUSE 3. primary monitor 4. other monitors where the window has group members on the same desktop 5. other monitors where the window has group members on other desktops 6. other monitors When a window is being placed in the BACKGROUND, use a monitor chosen in the following order: 1. same monitor as parent 2. other monitors where the window has group members on the same desktop 2a. primary monitor in this set 2b. other monitors in this set 3. other monitors where the window has group members on other desktops 3a. primary monitor in this set 3b. other monitors in this set 4. other monitors 4a. primary monitor in this set 4b. other monitors in this set Decide to focus the new window before placing it, so we know if it will be placed in the foreground or background. Always choose a single monitor, then place on it, rather than possibly moving to a "backup" monitor. Unpredictable monitor placement is horrible.
This commit is contained in:
parent
76ae19924d
commit
95535e8623
5 changed files with 338 additions and 280 deletions
|
@ -36,10 +36,10 @@
|
|||
<center>yes</center>
|
||||
<!-- whether to place windows in the center of the free area found or
|
||||
the top left corner -->
|
||||
<monitor>Active</monitor>
|
||||
<monitor>Primary</monitor>
|
||||
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||
the active window is -->
|
||||
the active window is, 'Primary' - only on the primary monitor -->
|
||||
<primaryMonitor>1</primaryMonitor>
|
||||
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||
focus cycling popup, or the desktop switch popup. It can be an index
|
||||
|
|
|
@ -192,7 +192,8 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
{
|
||||
ObClient *self;
|
||||
XSetWindowAttributes attrib_set;
|
||||
gboolean activate = FALSE;
|
||||
gboolean try_activate = FALSE;
|
||||
gboolean do_activate;
|
||||
ObAppSettings *settings;
|
||||
gboolean transient = FALSE;
|
||||
Rect place;
|
||||
|
@ -284,7 +285,7 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
FALSE, FALSE, TRUE, TRUE, FALSE, FALSE,
|
||||
settings->focus == 1))
|
||||
{
|
||||
activate = TRUE;
|
||||
try_activate = TRUE;
|
||||
}
|
||||
|
||||
/* remove the client's border */
|
||||
|
@ -298,6 +299,14 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
/* where the frame was placed is where the window was originally */
|
||||
place = self->area;
|
||||
|
||||
ob_debug("Going to try activate new window? %s",
|
||||
try_activate ? "yes" : "no");
|
||||
if (try_activate)
|
||||
do_activate = client_can_steal_focus(self, settings->focus,
|
||||
event_time(), launch_time);
|
||||
else
|
||||
do_activate = FALSE;
|
||||
|
||||
/* figure out placement for the window if the window is new */
|
||||
if (ob_state() == OB_STATE_RUNNING) {
|
||||
ob_debug("Positioned: %s @ %d %d",
|
||||
|
@ -316,7 +325,8 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
"program + user specified" :
|
||||
"BADNESS !?")))), place.width, place.height);
|
||||
|
||||
obplaced = place_client(self, &place.x, &place.y, settings);
|
||||
obplaced = place_client(self, do_activate, &place.x, &place.y,
|
||||
settings);
|
||||
|
||||
/* watch for buggy apps that ask to be placed at (0,0) when there is
|
||||
a strut there */
|
||||
|
@ -424,13 +434,30 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
client_apply_startup_state(self, place.x, place.y,
|
||||
place.width, place.height);
|
||||
|
||||
ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
|
||||
activate ? "yes" : "no");
|
||||
if (activate) {
|
||||
activate = client_can_steal_focus(self, settings->focus,
|
||||
event_time(), launch_time);
|
||||
/* grab mouse bindings before showing the window */
|
||||
mouse_grab_for_client(self, TRUE);
|
||||
|
||||
if (!activate) {
|
||||
/* this has to happen before we try focus the window, but we want it to
|
||||
happen after the client's stacking has been determined or it looks bad
|
||||
*/
|
||||
{
|
||||
gulong ignore_start;
|
||||
if (!config_focus_under_mouse)
|
||||
ignore_start = event_start_ignore_all_enters();
|
||||
|
||||
client_show(self);
|
||||
|
||||
if (!config_focus_under_mouse)
|
||||
event_end_ignore_all_enters(ignore_start);
|
||||
}
|
||||
|
||||
/* activate/hilight/raise the window */
|
||||
if (try_activate) {
|
||||
if (do_activate) {
|
||||
gboolean stacked = client_restore_session_stacking(self);
|
||||
client_present(self, FALSE, !stacked, TRUE);
|
||||
}
|
||||
else {
|
||||
/* if the client isn't stealing focus, then hilite it so the user
|
||||
knows it is there, but don't do this if we're restoring from a
|
||||
session */
|
||||
|
@ -450,27 +477,6 @@ void client_manage(Window window, ObPrompt *prompt)
|
|||
stacking_raise(CLIENT_AS_WINDOW(self));
|
||||
}
|
||||
|
||||
mouse_grab_for_client(self, TRUE);
|
||||
|
||||
/* this has to happen before we try focus the window, but we want it to
|
||||
happen after the client's stacking has been determined or it looks bad
|
||||
*/
|
||||
{
|
||||
gulong ignore_start;
|
||||
if (!config_focus_under_mouse)
|
||||
ignore_start = event_start_ignore_all_enters();
|
||||
|
||||
client_show(self);
|
||||
|
||||
if (!config_focus_under_mouse)
|
||||
event_end_ignore_all_enters(ignore_start);
|
||||
}
|
||||
|
||||
if (activate) {
|
||||
gboolean stacked = client_restore_session_stacking(self);
|
||||
client_present(self, FALSE, !stacked, TRUE);
|
||||
}
|
||||
|
||||
/* add to client list/map */
|
||||
client_list = g_list_append(client_list, self);
|
||||
window_add(&self->window, CLIENT_AS_WINDOW(self));
|
||||
|
@ -693,19 +699,15 @@ static gboolean client_can_steal_focus(ObClient *self,
|
|||
{
|
||||
gboolean steal;
|
||||
gboolean relative_focused;
|
||||
gboolean parent_focused;
|
||||
|
||||
steal = TRUE;
|
||||
|
||||
parent_focused = (focus_client != NULL &&
|
||||
client_search_focus_parent(self));
|
||||
relative_focused = (focus_client != NULL &&
|
||||
(client_search_focus_tree_full(self) != NULL ||
|
||||
client_search_focus_group_full(self) != NULL));
|
||||
|
||||
/* This is focus stealing prevention */
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Want to focus window 0x%x at time %u "
|
||||
ob_debug("Want to focus window 0x%x at time %u "
|
||||
"launched at %u (last user interaction time %u)",
|
||||
self->window, steal_time, launch_time,
|
||||
event_last_user_time);
|
||||
|
@ -721,15 +723,13 @@ static gboolean client_can_steal_focus(ObClient *self,
|
|||
!event_time_after(launch_time, screen_desktop_user_time))))
|
||||
{
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because its on another "
|
||||
"desktop\n");
|
||||
ob_debug("Not focusing the window because its on another desktop\n");
|
||||
}
|
||||
/* If something is focused... */
|
||||
else if (focus_client) {
|
||||
/* If the user is working in another window right now, then don't
|
||||
steal focus */
|
||||
if (!parent_focused &&
|
||||
if (!relative_focused &&
|
||||
event_last_user_time &&
|
||||
(!launch_time ||
|
||||
(event_time_after(event_last_user_time, launch_time) &&
|
||||
|
@ -738,17 +738,14 @@ static gboolean client_can_steal_focus(ObClient *self,
|
|||
steal_time - OB_EVENT_USER_TIME_DELAY))
|
||||
{
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because the user is "
|
||||
"working in another window that is not "
|
||||
"its parent");
|
||||
ob_debug("Not focusing the window because the user is "
|
||||
"working in another window that is not its relative");
|
||||
}
|
||||
/* If the new window is a transient (and its relatives aren't
|
||||
focused) */
|
||||
else if (client_has_parent(self) && !relative_focused) {
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because it is a "
|
||||
ob_debug("Not focusing the window because it is a "
|
||||
"transient, and its relatives aren't focused");
|
||||
}
|
||||
/* Don't steal focus from globally active clients.
|
||||
|
@ -758,16 +755,14 @@ static gboolean client_can_steal_focus(ObClient *self,
|
|||
focus_client->focus_notify))
|
||||
{
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because a globally "
|
||||
ob_debug("Not focusing the window because a globally "
|
||||
"active client has focus");
|
||||
}
|
||||
/* Don't move focus if it's not going to go to this window
|
||||
anyway */
|
||||
else if (client_focus_target(self) != self) {
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because another window "
|
||||
ob_debug("Not focusing the window because another window "
|
||||
"would get the focus anyway");
|
||||
}
|
||||
/* Don't move focus if the window is not visible on the current
|
||||
|
@ -777,15 +772,13 @@ static gboolean client_can_steal_focus(ObClient *self,
|
|||
!relative_focused)
|
||||
{
|
||||
steal = FALSE;
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Not focusing the window because it is on "
|
||||
ob_debug("Not focusing the window because it is on "
|
||||
"another desktop and no relatives are focused ");
|
||||
}
|
||||
}
|
||||
|
||||
if (!steal)
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"Focus stealing prevention activated for %s at "
|
||||
ob_debug("Focus stealing prevention activated for %s at "
|
||||
"time %u (last user interaction time %u)",
|
||||
self->title, steal_time, event_last_user_time);
|
||||
return steal;
|
||||
|
|
|
@ -582,6 +582,8 @@ static void parse_placement(xmlNodePtr node, gpointer d)
|
|||
config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
|
||||
else if (obt_xml_node_contains(n, "mouse"))
|
||||
config_place_monitor = OB_PLACE_MONITOR_MOUSE;
|
||||
else if (obt_xml_node_contains(n, "any"))
|
||||
config_place_monitor = OB_PLACE_MONITOR_ANY;
|
||||
}
|
||||
if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
|
||||
config_primary_monitor_index = obt_xml_node_int(n);
|
||||
|
@ -1003,7 +1005,7 @@ void config_startup(ObtXmlInst *i)
|
|||
|
||||
config_place_policy = OB_PLACE_POLICY_SMART;
|
||||
config_place_center = TRUE;
|
||||
config_place_monitor = OB_PLACE_MONITOR_ANY;
|
||||
config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
|
||||
|
||||
config_primary_monitor_index = 1;
|
||||
config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
|
||||
|
|
326
openbox/place.c
326
openbox/place.c
|
@ -28,129 +28,207 @@
|
|||
|
||||
extern ObDock *dock;
|
||||
|
||||
static void add_choice(guint *choice, guint mychoice)
|
||||
{
|
||||
guint i;
|
||||
for (i = 0; i < screen_num_monitors; ++i) {
|
||||
if (choice[i] == mychoice)
|
||||
return;
|
||||
else if (choice[i] == screen_num_monitors) {
|
||||
choice[i] = mychoice;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Rect *pick_pointer_head(ObClient *c)
|
||||
{
|
||||
return screen_area(c->desktop, screen_monitor_pointer(), NULL);
|
||||
}
|
||||
|
||||
/*! Pick a monitor to place a window on. */
|
||||
static Rect **pick_head(ObClient *c)
|
||||
/* use the following priority lists for pick_head()
|
||||
|
||||
When a window is being placed in the FOREGROUND, use a monitor chosen in
|
||||
the following order:
|
||||
1. same monitor as parent
|
||||
2. primary monitor if placement=PRIMARY
|
||||
active monitor if placement=ACTIVE
|
||||
pointer monitor if placement=MOUSE
|
||||
3. primary monitor
|
||||
4. other monitors where the window has group members on the same desktop
|
||||
5. other monitors where the window has group members on other desktops
|
||||
6. other monitors
|
||||
|
||||
When a window is being placed in the BACKGROUND, use a monitor chosen in the
|
||||
following order:
|
||||
1. same monitor as parent
|
||||
2. other monitors where the window has group members on the same desktop
|
||||
2a. primary monitor in this set
|
||||
2b. other monitors in this set
|
||||
3. other monitors where the window has group members on other desktops
|
||||
3a. primary monitor in this set
|
||||
3b. other monitors in this set
|
||||
4. other monitors
|
||||
4a. primary monitor in this set
|
||||
4b. other monitors in this set
|
||||
*/
|
||||
|
||||
/*! One for each possible head, used to sort them in order of precedence. */
|
||||
typedef struct {
|
||||
guint monitor;
|
||||
guint flags;
|
||||
} ObPlaceHead;
|
||||
|
||||
/*! Flags for ObPlaceHead */
|
||||
enum {
|
||||
HEAD_PARENT = 1 << 0, /* parent's monitor */
|
||||
HEAD_PLACED = 1 << 1, /* chosen monitor by placement */
|
||||
HEAD_PRIMARY = 1 << 2, /* primary monitor */
|
||||
HEAD_GROUP_DESK = 1 << 3, /* has a group member on the same desktop */
|
||||
HEAD_GROUP = 1 << 4, /* has a group member on another desktop */
|
||||
};
|
||||
|
||||
gint cmp_foreground(const void *a, const void *b)
|
||||
{
|
||||
Rect **area;
|
||||
guint *choice;
|
||||
guint i;
|
||||
gint px, py;
|
||||
ObClient *p;
|
||||
const ObPlaceHead *h1 = a;
|
||||
const ObPlaceHead *h2 = b;
|
||||
gint i = 0;
|
||||
|
||||
area = g_new(Rect*, screen_num_monitors);
|
||||
choice = g_new(guint, screen_num_monitors);
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
choice[i] = screen_num_monitors; /* make them all invalid to start */
|
||||
if (h1->monitor == h2->monitor) return 0;
|
||||
|
||||
/* try direct parent first */
|
||||
if ((p = client_direct_parent(c))) {
|
||||
add_choice(choice, client_monitor(p));
|
||||
ob_debug("placement adding choice %d for parent",
|
||||
client_monitor(p));
|
||||
if (h1->flags & HEAD_PARENT) --i;
|
||||
if (h2->flags & HEAD_PARENT) ++i;
|
||||
if (i) return i;
|
||||
|
||||
if (h1->flags & HEAD_PLACED) --i;
|
||||
if (h2->flags & HEAD_PLACED) ++i;
|
||||
if (i) return i;
|
||||
|
||||
if (h1->flags & HEAD_PRIMARY) --i;
|
||||
if (h2->flags & HEAD_PRIMARY) ++i;
|
||||
if (i) return i;
|
||||
|
||||
if (h1->flags & HEAD_GROUP_DESK) --i;
|
||||
if (h2->flags & HEAD_GROUP_DESK) ++i;
|
||||
if (i) return i;
|
||||
|
||||
if (h1->flags & HEAD_GROUP) --i;
|
||||
if (h2->flags & HEAD_GROUP) ++i;
|
||||
if (i) return i;
|
||||
|
||||
return h1->monitor - h2->monitor;
|
||||
}
|
||||
|
||||
gint cmp_background(const void *a, const void *b)
|
||||
{
|
||||
const ObPlaceHead *h1 = a;
|
||||
const ObPlaceHead *h2 = b;
|
||||
gint i = 0;
|
||||
|
||||
if (h1->monitor == h2->monitor) return 0;
|
||||
|
||||
if (h1->flags & HEAD_PARENT) --i;
|
||||
if (h2->flags & HEAD_PARENT) ++i;
|
||||
if (i) return i;
|
||||
|
||||
if (h1->flags & HEAD_GROUP_DESK || h2->flags & HEAD_GROUP_DESK) {
|
||||
if (h1->flags & HEAD_GROUP_DESK) --i;
|
||||
if (h2->flags & HEAD_GROUP_DESK) ++i;
|
||||
if (i) return i;
|
||||
if (h1->flags & HEAD_PRIMARY) --i;
|
||||
if (h2->flags & HEAD_PRIMARY) ++i;
|
||||
if (i) return i;
|
||||
}
|
||||
|
||||
/* more than one window in its group (more than just this window) */
|
||||
if (client_has_group_siblings(c)) {
|
||||
if (h1->flags & HEAD_GROUP || h2->flags & HEAD_GROUP) {
|
||||
if (h1->flags & HEAD_GROUP) --i;
|
||||
if (h2->flags & HEAD_GROUP) ++i;
|
||||
if (i) return i;
|
||||
if (h1->flags & HEAD_PRIMARY) --i;
|
||||
if (h2->flags & HEAD_PRIMARY) ++i;
|
||||
if (i) return i;
|
||||
}
|
||||
|
||||
if (h1->flags & HEAD_PRIMARY) --i;
|
||||
if (h2->flags & HEAD_PRIMARY) ++i;
|
||||
if (i) return i;
|
||||
|
||||
return h1->monitor - h2->monitor;
|
||||
}
|
||||
|
||||
/*! Pick a monitor to place a window on. */
|
||||
static Rect *pick_head(ObClient *c, gboolean foreground)
|
||||
{
|
||||
Rect *area;
|
||||
ObPlaceHead *choice;
|
||||
guint i;
|
||||
ObClient *p;
|
||||
GSList *it;
|
||||
|
||||
/* try on the client's desktop */
|
||||
for (it = c->group->members; it; it = g_slist_next(it)) {
|
||||
ObClient *itc = it->data;
|
||||
if (itc != c &&
|
||||
(itc->desktop == c->desktop ||
|
||||
itc->desktop == DESKTOP_ALL || c->desktop == DESKTOP_ALL))
|
||||
{
|
||||
add_choice(choice, client_monitor(it->data));
|
||||
ob_debug("placement adding choice %d for group sibling",
|
||||
client_monitor(it->data));
|
||||
}
|
||||
choice = g_new(ObPlaceHead, screen_num_monitors);
|
||||
for (i = 0; i < screen_num_monitors; ++i) {
|
||||
choice[i].monitor = i;
|
||||
choice[i].flags = 0;
|
||||
}
|
||||
|
||||
/* try on all desktops */
|
||||
/* find monitors with group members */
|
||||
for (it = c->group->members; it; it = g_slist_next(it)) {
|
||||
ObClient *itc = it->data;
|
||||
if (itc != c) {
|
||||
add_choice(choice, client_monitor(it->data));
|
||||
ob_debug("placement adding choice %d for group sibling on "
|
||||
"another desktop", client_monitor(it->data));
|
||||
guint m = client_monitor(itc);
|
||||
|
||||
if (m < screen_num_monitors) {
|
||||
if (screen_compare_desktops(itc->desktop, c->desktop))
|
||||
choice[m].flags |= HEAD_GROUP_DESK;
|
||||
else
|
||||
choice[m].flags |= HEAD_GROUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* skip this if placing by the mouse position */
|
||||
if (focus_client && client_normal(focus_client) &&
|
||||
config_place_monitor != OB_PLACE_MONITOR_MOUSE)
|
||||
i = screen_monitor_primary(FALSE);
|
||||
if (i < screen_num_monitors) {
|
||||
choice[i].flags |= HEAD_PRIMARY;
|
||||
if (config_place_monitor == OB_PLACE_MONITOR_PRIMARY)
|
||||
choice[i].flags |= HEAD_PLACED;
|
||||
}
|
||||
|
||||
/* direct parent takes highest precedence */
|
||||
if ((p = client_direct_parent(c))) {
|
||||
i = client_monitor(p);
|
||||
if (i < screen_num_monitors)
|
||||
choice[i].flags |= HEAD_PARENT;
|
||||
}
|
||||
|
||||
qsort(choice, screen_num_monitors, sizeof(ObPlaceHead),
|
||||
foreground ? cmp_foreground : cmp_background);
|
||||
|
||||
/* save the areas of the monitors in order of their being chosen */
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
{
|
||||
add_choice(choice, client_monitor(focus_client));
|
||||
ob_debug("placement adding choice %d for normal focused window",
|
||||
client_monitor(focus_client));
|
||||
ob_debug("placement choice %d is monitor %d", i, choice[i].monitor);
|
||||
if (choice[i].flags & HEAD_PARENT)
|
||||
ob_debug(" - parent on monitor");
|
||||
if (choice[i].flags & HEAD_PLACED)
|
||||
ob_debug(" - placement choice");
|
||||
if (choice[i].flags & HEAD_PRIMARY)
|
||||
ob_debug(" - primary monitor");
|
||||
if (choice[i].flags & HEAD_GROUP_DESK)
|
||||
ob_debug(" - group on same desktop");
|
||||
if (choice[i].flags & HEAD_GROUP)
|
||||
ob_debug(" - group on other desktop");
|
||||
}
|
||||
|
||||
screen_pointer_pos(&px, &py);
|
||||
|
||||
for (i = 0; i < screen_num_monitors; i++) {
|
||||
const Rect *monitor = screen_physical_area_monitor(i);
|
||||
gboolean contain = RECT_CONTAINS(*monitor, px, py);
|
||||
if (contain) {
|
||||
add_choice(choice, i);
|
||||
ob_debug("placement adding choice %d for mouse pointer", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* add any leftover choices */
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
add_choice(choice, i);
|
||||
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
area[i] = screen_area(c->desktop, choice[i], NULL);
|
||||
area = screen_area(c->desktop, choice[0].monitor, NULL);
|
||||
|
||||
g_free(choice);
|
||||
|
||||
/* return the area for the chosen monitor */
|
||||
return area;
|
||||
}
|
||||
|
||||
static gboolean place_random(ObClient *client, gint *x, gint *y)
|
||||
static gboolean place_random(ObClient *client, Rect *area, gint *x, gint *y)
|
||||
{
|
||||
gint l, r, t, b;
|
||||
Rect **areas;
|
||||
guint i;
|
||||
|
||||
areas = pick_head(client);
|
||||
i = (config_place_monitor != OB_PLACE_MONITOR_ANY) ?
|
||||
0 : g_random_int_range(0, screen_num_monitors);
|
||||
ob_debug("placing randomly");
|
||||
|
||||
l = areas[i]->x;
|
||||
t = areas[i]->y;
|
||||
r = areas[i]->x + areas[i]->width - client->frame->area.width;
|
||||
b = areas[i]->y + areas[i]->height - client->frame->area.height;
|
||||
l = area->x;
|
||||
t = area->y;
|
||||
r = area->x + area->width - client->frame->area.width;
|
||||
b = area->y + area->height - client->frame->area.height;
|
||||
|
||||
if (r > l) *x = g_random_int_range(l, r + 1);
|
||||
else *x = areas[i]->x;
|
||||
else *x = area->x;
|
||||
if (b > t) *y = g_random_int_range(t, b + 1);
|
||||
else *y = areas[i]->y;
|
||||
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
g_slice_free(Rect, areas[i]);
|
||||
g_free(areas);
|
||||
else *y = area->y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -228,31 +306,25 @@ enum {
|
|||
IGNORE_END = 7
|
||||
};
|
||||
|
||||
static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
|
||||
static gboolean place_nooverlap(ObClient *c, Rect *area, gint *x, gint *y)
|
||||
{
|
||||
Rect **areas;
|
||||
gint ignore;
|
||||
gboolean ret;
|
||||
gint maxsize;
|
||||
GSList *spaces = NULL, *sit, *maxit;
|
||||
guint i;
|
||||
|
||||
areas = pick_head(c);
|
||||
ob_debug("placing nonoverlap");
|
||||
|
||||
ret = FALSE;
|
||||
maxsize = 0;
|
||||
maxit = NULL;
|
||||
|
||||
/* try ignoring different things to find empty space */
|
||||
for (ignore = 0; ignore < IGNORE_END && !ret; ignore++) {
|
||||
/* try all monitors in order of preference, but only the first one
|
||||
if config_place_monitor is MOUSE or ACTIVE */
|
||||
for (i = 0; (i < (config_place_monitor != OB_PLACE_MONITOR_ANY ?
|
||||
1 : screen_num_monitors) && !ret); ++i)
|
||||
{
|
||||
GList *it;
|
||||
|
||||
/* add the whole monitor */
|
||||
spaces = area_add(spaces, areas[i]);
|
||||
spaces = area_add(spaces, area);
|
||||
|
||||
/* go thru all the windows */
|
||||
for (it = client_list; it; it = g_list_next(it)) {
|
||||
|
@ -335,11 +407,7 @@ static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
|
|||
spaces = g_slist_delete_link(spaces, spaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
g_slice_free(Rect, areas[i]);
|
||||
g_free(areas);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -349,6 +417,8 @@ static gboolean place_under_mouse(ObClient *client, gint *x, gint *y)
|
|||
gint px, py;
|
||||
Rect *area;
|
||||
|
||||
ob_debug("placing under mouse");
|
||||
|
||||
if (!screen_pointer_pos(&px, &py))
|
||||
return FALSE;
|
||||
area = pick_pointer_head(client);
|
||||
|
@ -376,27 +446,17 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
|
|||
if (!settings || (settings && !settings->pos_given))
|
||||
return FALSE;
|
||||
|
||||
ob_debug("placing by per-app settings");
|
||||
|
||||
/* Find which head the pointer is on */
|
||||
if (settings->monitor == 0)
|
||||
/* this can return NULL */
|
||||
screen = pick_pointer_head(client);
|
||||
else if (settings->monitor > 0 &&
|
||||
(guint)settings->monitor <= screen_num_monitors)
|
||||
screen = screen_area(client->desktop, (guint)settings->monitor - 1,
|
||||
NULL);
|
||||
|
||||
/* if we have't found a screen yet.. */
|
||||
if (!screen) {
|
||||
Rect **areas;
|
||||
guint i;
|
||||
|
||||
areas = pick_head(client);
|
||||
screen = areas[0];
|
||||
|
||||
/* don't free the first one, it's being set as "screen" */
|
||||
for (i = 1; i < screen_num_monitors; ++i)
|
||||
g_slice_free(Rect, areas[i]);
|
||||
g_free(areas);
|
||||
else {
|
||||
guint m = settings->monitor;
|
||||
if (m < 1 || m > screen_num_monitors)
|
||||
m = screen_monitor_primary(TRUE) + 1;
|
||||
screen = screen_area(client->desktop, m - 1, NULL);
|
||||
}
|
||||
|
||||
if (settings->position.x.center)
|
||||
|
@ -423,12 +483,16 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
|
||||
static gboolean place_transient_splash(ObClient *client, Rect *area,
|
||||
gint *x, gint *y)
|
||||
{
|
||||
if (client->type == OB_CLIENT_TYPE_DIALOG) {
|
||||
GSList *it;
|
||||
gboolean first = TRUE;
|
||||
gint l, r, t, b;
|
||||
|
||||
ob_debug("placing dialog");
|
||||
|
||||
for (it = client->parents; it; it = g_slist_next(it)) {
|
||||
ObClient *m = it->data;
|
||||
if (!m->iconic) {
|
||||
|
@ -456,17 +520,10 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
|
|||
if (client->type == OB_CLIENT_TYPE_DIALOG ||
|
||||
client->type == OB_CLIENT_TYPE_SPLASH)
|
||||
{
|
||||
Rect **areas;
|
||||
guint i;
|
||||
ob_debug("placing dialog or splash");
|
||||
|
||||
areas = pick_head(client);
|
||||
|
||||
*x = (areas[0]->width - client->frame->area.width) / 2 + areas[0]->x;
|
||||
*y = (areas[0]->height - client->frame->area.height) / 2 + areas[0]->y;
|
||||
|
||||
for (i = 0; i < screen_num_monitors; ++i)
|
||||
g_slice_free(Rect, areas[i]);
|
||||
g_free(areas);
|
||||
*x = (area->width - client->frame->area.width) / 2 + area->x;
|
||||
*y = (area->height - client->frame->area.height) / 2 + area->y;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -475,9 +532,10 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
|
|||
|
||||
/*! Return TRUE if openbox chose the position for the window, and FALSE if
|
||||
the application chose it */
|
||||
gboolean place_client(ObClient *client, gint *x, gint *y,
|
||||
gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y,
|
||||
ObAppSettings *settings)
|
||||
{
|
||||
Rect *area;
|
||||
gboolean ret;
|
||||
|
||||
/* per-app settings override program specified position
|
||||
|
@ -488,15 +546,19 @@ gboolean place_client(ObClient *client, gint *x, gint *y,
|
|||
!(settings && settings->pos_given)))
|
||||
return FALSE;
|
||||
|
||||
area = pick_head(client, foreground);
|
||||
|
||||
/* try a number of methods */
|
||||
ret = place_per_app_setting(client, x, y, settings) ||
|
||||
place_transient_splash(client, x, y) ||
|
||||
place_transient_splash(client, area, x, y) ||
|
||||
(config_place_policy == OB_PLACE_POLICY_MOUSE &&
|
||||
place_under_mouse(client, x, y)) ||
|
||||
place_nooverlap(client, x, y) ||
|
||||
place_random(client, x, y);
|
||||
place_nooverlap(client, area, x, y) ||
|
||||
place_random(client, area, x, y);
|
||||
g_assert(ret);
|
||||
|
||||
g_slice_free(Rect, area);
|
||||
|
||||
/* get where the client should be */
|
||||
frame_frame_gravity(client->frame, x, y);
|
||||
return TRUE;
|
||||
|
|
|
@ -35,10 +35,11 @@ typedef enum
|
|||
{
|
||||
OB_PLACE_MONITOR_ANY,
|
||||
OB_PLACE_MONITOR_ACTIVE,
|
||||
OB_PLACE_MONITOR_MOUSE
|
||||
OB_PLACE_MONITOR_MOUSE,
|
||||
OB_PLACE_MONITOR_PRIMARY
|
||||
} ObPlaceMonitor;
|
||||
|
||||
gboolean place_client(struct _ObClient *client, gint *x, gint *y,
|
||||
struct _ObAppSettings *settings);
|
||||
gboolean place_client(struct _ObClient *client, gboolean foreground,
|
||||
gint *x, gint *y, struct _ObAppSettings *settings);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue