/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-client.c for the Openbox window manager
-Copyright (c) 2003 Ben Jansens
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-See the COPYING file for a copy of the GNU General Public License.
+
+ client.c for the Openbox window manager
+ Copyright (c) 2004 Mikael Magnusson
+ Copyright (c) 2003 Ben Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
*/
#include "client.h"
/*! The event mask to grab on client windows */
#define CLIENT_EVENTMASK (PropertyChangeMask | FocusChangeMask | \
- StructureNotifyMask)
+ StructureNotifyMask)
#define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
- ButtonMotionMask)
+ ButtonMotionMask)
typedef struct
{
}
/*
- void client_foreach_transient(ObClient *self, ObClientForeachFunc func, void *data)
+ void client_foreach_transient(ObClient *self, ObClientForeachFunc func, gpointer data)
{
GSList *it;
}
}
- void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, void *data)
+ void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, gpointer data)
{
if (self->transient_for) {
if (self->transient_for != OB_TRAN_GROUP) {
place_client(self, &x, &y);
- /* make sure the window is visible */
- client_find_onscreen(self, &x, &y,
- self->frame->area.width,
- self->frame->area.height,
- /* non-normal clients has less rules, and
- windows that are being restored from a session
- do also. we can assume you want it back where
- you saved it */
- client_normal(self) && !self->session);
-
- if (x != ox || y != oy)
- client_move(self, x, y);
+ /* make sure the window is visible.
+
+ this is about the rude parameter:
+ non-normal clients has less rules, and
+ windows that are being restored from a session
+ do also. we can assume you want it back where
+ you saved it */
+ client_move_onscreen(self, client_normal(self) && !self->session);
}
+ keyboard_grab_for_client(self, TRUE);
+ mouse_grab_for_client(self, TRUE);
+
client_showhide(self);
/* use client_focus instead of client_activate cuz client_activate does
/* update the list hints */
client_set_list();
- keyboard_grab_for_client(self, TRUE);
- mouse_grab_for_client(self, TRUE);
-
ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
}
keyboard_grab_for_client(self, FALSE);
mouse_grab_for_client(self, FALSE);
+ /* potentially fix focusLast */
+ if (config_focus_last)
+ grab_pointer(TRUE, OB_CURSOR_NONE);
+
/* remove the window from our save set */
XChangeSaveSet(ob_display, self->window, SetModeDelete);
/* tell our parent(s) that we're gone */
if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
- GSList *it;
-
for (it = self->group->members; it; it = g_slist_next(it))
if (it->data != self)
((ObClient*)it->data)->transients =
/* update the list hints */
client_set_list();
+
+ if (config_focus_last)
+ grab_pointer(FALSE, OB_CURSOR_NONE);
}
static void client_urgent_notify(ObClient *self)
/* XXX watch for xinerama dead areas */
- a = screen_area(self->desktop);
+ /* a = screen_area(self->desktop); */
+ a = screen_physical_area_monitor(client_monitor(self));
if (client_normal(self)) {
if (!self->strut.right && *x >= a->x + a->width - 1)
*x = a->x + a->width - self->frame->area.width;
client_get_mwm_hints(self);
client_get_type(self);/* this can change the mwmhints for special cases */
+ /* The transient hint is used to pick a type, but the type can also affect
+ transiency (dialogs are always made transients). This is Havoc's idea,
+ but it is needed to make some apps work right (eg tsclient). */
+ client_update_transient_for(self);
+
client_get_state(self);
{
}
}
}
+ } else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
+ self->transient = TRUE;
+ target = OB_TRAN_GROUP;
} else
self->transient = FALSE;
/* dont let mwm hints kill the close button
if (! (self->mwmhints.functions & MwmFunc_Close))
self->functions &= ~OB_CLIENT_FUNC_CLOSE; */
- }
+ }
}
if (!(self->functions & OB_CLIENT_FUNC_SHADE))
/* finally, the user can have requested no decorations, which overrides
everything (but doesnt give it a border if it doesnt have one) */
- if (self->undecorated)
- self->decorations &= OB_FRAME_DECOR_BORDER;
+ if (self->undecorated) {
+ if (config_theme_keepborder)
+ self->decorations &= OB_FRAME_DECOR_BORDER;
+ else
+ self->decorations = 0;
+ }
/* if we don't have a titlebar, then we cannot shade! */
if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
old_title = self->title;
/* try netwm */
- if (!PROP_GETS(self->window, net_wm_name, utf8, &data))
+ if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
/* try old x stuff */
- if (!PROP_GETS(self->window, wm_name, locale, &data))
- data = g_strdup("Unnamed Window");
+ if (!PROP_GETS(self->window, wm_name, locale, &data)) {
+ // http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+ if (self->transient) {
+ data = g_strdup("");
+ goto no_number;
+ } else
+ data = g_strdup("Unnamed Window");
+ }
+ }
/* did the title change? then reset the title_count */
if (old_title && 0 != strncmp(old_title, data, strlen(data)))
}
PROP_SETS(self->window, net_wm_visible_name, data);
-
+no_number:
self->title = data;
if (self->frame)
w -= self->base_size.width;
h -= self->base_size.height;
- if (self->min_ratio)
- if (h * self->min_ratio > w) {
- h = (gint)(w / self->min_ratio);
+ if (!self->fullscreen) {
+ if (self->min_ratio)
+ if (h * self->min_ratio > w) {
+ h = (gint)(w / self->min_ratio);
- /* you cannot resize to nothing */
- if (h < 1) {
- h = 1;
- w = (gint)(h * self->min_ratio);
+ /* you cannot resize to nothing */
+ if (h < 1) {
+ h = 1;
+ w = (gint)(h * self->min_ratio);
+ }
}
- }
- if (self->max_ratio)
- if (h * self->max_ratio < w) {
- h = (gint)(w / self->max_ratio);
-
- /* you cannot resize to nothing */
- if (h < 1) {
- h = 1;
- w = (gint)(h * self->min_ratio);
+ if (self->max_ratio)
+ if (h * self->max_ratio < w) {
+ h = (gint)(w / self->max_ratio);
+
+ /* you cannot resize to nothing */
+ if (h < 1) {
+ h = 1;
+ w = (gint)(h * self->min_ratio);
+ }
}
- }
+ }
w += self->base_size.width;
h += self->base_size.height;
resizing in redraw mode */
send_resize_client = ((!user && resized) ||
(user && (final ||
- (resized && config_redraw_resize))));
+ (resized && config_resize_redraw))));
- /* if the client is enlarging, the resize the client before the frame */
+ /* if the client is enlarging, then resize the client before the frame */
if (send_resize_client && user && (w > oldw || h > oldh))
XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
gboolean max_horz = self->max_horz;
gboolean max_vert = self->max_vert;
gboolean modal = self->modal;
+ gboolean iconic = self->iconic;
gint i;
if (!(action == prop_atoms.net_wm_state_add ||
action = self->skip_pager ?
prop_atoms.net_wm_state_remove :
prop_atoms.net_wm_state_add;
+ else if (state == prop_atoms.net_wm_state_hidden)
+ action = self->iconic ?
+ prop_atoms.net_wm_state_remove :
+ prop_atoms.net_wm_state_add;
else if (state == prop_atoms.net_wm_state_fullscreen)
action = fullscreen ?
prop_atoms.net_wm_state_remove :
self->skip_taskbar = TRUE;
} else if (state == prop_atoms.net_wm_state_skip_pager) {
self->skip_pager = TRUE;
+ } else if (state == prop_atoms.net_wm_state_hidden) {
+ iconic = TRUE;
} else if (state == prop_atoms.net_wm_state_fullscreen) {
fullscreen = TRUE;
} else if (state == prop_atoms.net_wm_state_above) {
self->skip_taskbar = FALSE;
} else if (state == prop_atoms.net_wm_state_skip_pager) {
self->skip_pager = FALSE;
+ } else if (state == prop_atoms.net_wm_state_hidden) {
+ iconic = FALSE;
} else if (state == prop_atoms.net_wm_state_fullscreen) {
fullscreen = FALSE;
} else if (state == prop_atoms.net_wm_state_above) {
transients needs to change */
client_raise(self);
}
+ if (iconic != self->iconic)
+ client_iconify(self, iconic, FALSE);
+
client_calc_layer(self);
client_change_state(self); /* change the hint to reflect these changes */
}
void client_lower(ObClient *self)
{
- action_run_string("Raise", self);
+ action_run_string("Lower", self);
}
gboolean client_focused(ObClient *self)
continue;
if (!client_normal(cur))
continue;
- if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ /* using c->desktop instead of screen_desktop doesn't work if the
+ * current window was omnipresent, hope this doesn't have any other
+ * side effects */
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
continue;
if(cur->iconic)
continue;
}
}
+/* 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;
*/
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:
/* 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;
continue;
if(!client_normal(cur))
continue;
- if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
continue;
if(cur->iconic)
continue;
+ if(cur->layer < c->layer && !config_resist_layers_below)
+ continue;
his_edge_start = cur->frame->area.x;
his_edge_end = cur->frame->area.x + cur->frame->area.width;
/* 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;
continue;
if(!client_normal(cur))
continue;
- if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
continue;
if(cur->iconic)
continue;
+ if(cur->layer < c->layer && !config_resist_layers_below)
+ continue;
his_edge_start = cur->frame->area.x;
his_edge_end = cur->frame->area.x + cur->frame->area.width;
/* 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;
continue;
if(!client_normal(cur))
continue;
- if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
continue;
if(cur->iconic)
continue;
+ if(cur->layer < c->layer && !config_resist_layers_below)
+ continue;
his_edge_start = cur->frame->area.y;
his_edge_end = cur->frame->area.y + cur->frame->area.height;
/* 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;
continue;
if(!client_normal(cur))
continue;
- if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
continue;
if(cur->iconic)
continue;
+ if(cur->layer < c->layer && !config_resist_layers_below)
+ continue;
his_edge_start = cur->frame->area.y;
his_edge_end = cur->frame->area.y + cur->frame->area.height;
/* not implemented */
default:
g_assert_not_reached();
+ dest = 0; /* suppress warning */
}
return dest;
}