<placement>
<policy>Smart</policy>
<!-- 'Smart' or 'UnderMouse' -->
- <center>yes</center>
- <!-- whether to place windows in the center of the free area found or
- the top left corner -->
<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
-->
<keepBorder>yes</keepBorder>
<animateIconify>yes</animateIconify>
+ <flashFrameDelay>600</flashFrameDelay>
+ <flashFrameDuration>5000</flashFrameDuration>
<font place="ActiveWindow">
<name>sans</name>
<size>8</size>
submenu will not be shown until it is clicked on -->
<submenuHideDelay>400</submenuHideDelay>
<!-- time to delay before hiding a submenu when selecting another
- entry in parent menu -->
+ entry in parent menu
if this is a negative value, then the delay is infinite and the
submenu will not be hidden until a different submenu is opened -->
- <applicationIcons>yes</applicationIcons>
+ <showIcons>yes</showIcons>
<!-- controls if icons appear in the client-list-(combined-)menu -->
<manageDesktops>yes</manageDesktops>
<!-- show the manage desktops section in the client-list-(combined-)menu -->
<application name="the window's _OB_APP_NAME property (see obxprop)"
class="the window's _OB_APP_CLASS property (see obxprop)"
+ groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
+ groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
role="the window's _OB_APP_ROLE property (see obxprop)"
title="the window's _OB_APP_TITLE property (see obxprop)"
type="the window's _OB_APP_TYPE property (see obxprob)..
# applications who refuse to behave
<x>center</x>
# a number like 50, or 'center' to center on screen. use a negative number
- # to start from the right (or bottom for <y>), ie -50 is 50 pixels from the
- # right edge (or bottom).
+ # to start from the right (or bottom for <y>), ie -50 is 50 pixels from
+ # the right edge (or bottom). use 'default' to specify using value
+ # provided by the application, or chosen by openbox, instead.
<y>200</y>
<monitor>1</monitor>
# specifies the monitor in a xinerama setup.
# 1 is the first head, or 'mouse' for wherever the mouse is
</position>
+ <size>
+ # the size to make the window.
+ <width>20</width>
+ # a number like 20, or 'default' to use the size given by the application.
+ # you can use fractions such as 1/2 or percentages such as 75% in which
+ # case the value is relative to the size of the monitor that the window
+ # appears on.
+ <height>30%</height>
+ </size>
+
<focus>yes</focus>
# if the window should try be given focus when it appears. if this is set
# to yes it doesn't guarantee the window will be given focus. some
<maximized>true</maximized>
# 'Horizontal', 'Vertical' or boolean (yes/no)
+
+ <opacity>255</opacity>
+ # make the window semi-transparent
+ # value between 0 and 255, inclusive; 0 invisible, 255 fully opaque
</application>
# end of the example
</xsd:annotation>
<xsd:sequence>
<xsd:element minOccurs="0" name="policy" type="ob:placementpolicy"/>
- <xsd:element minOccurs="0" name="center" type="ob:bool"/>
<xsd:element minOccurs="0" name="monitor" type="ob:placementmonitor"/>
- <xsd:element minOccurs="0" name="monitor" type="ob:primarymonitor"/>
+ <xsd:element minOccurs="0" name="primaryMonitor" type="ob:primarymonitor"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="margins">
<xsd:element minOccurs="0" name="titleLayout" type="xsd:string"/>
<xsd:element minOccurs="0" name="keepBorder" type="ob:bool"/>
<xsd:element minOccurs="0" name="animateIconify" type="ob:bool"/>
+ <xsd:element minOccurs="0" name="flashFrameDelay" type="ob:integer"/>
+ <xsd:element minOccurs="0" name="flashFrameDuration" type="ob:integer"/>
<xsd:element minOccurs="0" maxOccurs="unbounded" name="font" type="ob:font"/>
</xsd:sequence>
</xsd:complexType>
</xsd:all>
<xsd:attribute name="force" type="ob:bool"/>
</xsd:complexType>
+ <xsd:complexType name="window_size">
+ <xsd:all>
+ <xsd:element name="width" type="ob:size_value"/>
+ <xsd:element name="height" type="ob:size_value"/>
+ </xsd:all>
+ </xsd:complexType>
<xsd:complexType name="application">
<xsd:all>
<xsd:element minOccurs="0" name="decor" type="ob:bool"/>
<xsd:element minOccurs="0" name="shade" type="ob:bool"/>
<xsd:element minOccurs="0" name="position" type="ob:window_position"/>
+ <xsd:element minOccurs="0" name="size" type="ob:window_size"/>
<xsd:element minOccurs="0" name="focus" type="xsd:string"/>
<xsd:element minOccurs="0" name="desktop" type="xsd:integer"/>
<xsd:element minOccurs="0" name="layer" type="ob:layer"/>
<xsd:element minOccurs="0" name="skip_taskbar" type="ob:bool"/>
<xsd:element minOccurs="0" name="fullscreen" type="ob:bool"/>
<xsd:element minOccurs="0" name="maximized" type="ob:maximization"/>
+ <xsd:element minOccurs="0" name="opacity" type="xsd:unsignedByte"/>
</xsd:all>
<!-- at least one of these must be present -->
<xsd:attribute name="role" type="xsd:string"/>
<xsd:enumeration value="InactiveWindow"/>
<xsd:enumeration value="MenuHeader"/>
<xsd:enumeration value="MenuItem"/>
- <xsd:enumeration value="OnScreenDisplay"/>
+ <xsd:enumeration value="ActiveOnScreenDisplay"/>
+ <xsd:enumeration value="InactiveOnScreenDisplay"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="fontweight">
<xsd:restriction base="xsd:string">
<!-- ob: atoi($_) unless $_ eq 'center'; -->
<!-- I think the regexp DTRT WRT atoi. -->
- <xsd:pattern value="center|-?(0|[1-9][0-9]*)"/>
+ <xsd:pattern value="default|center|-?(0|[1-9][0-9]*)(|%|/[1-9][0-9]*)"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="size_value">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="default|([1-9][0-9]*)(|%|/[1-9][0-9]*)"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="mouse_or_int">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Mouse"/>
<xsd:enumeration value="Active"/>
- <xsd:enumeration value="[0-9][0-9][0-9][0-9][0-9]"/>
+ <xsd:pattern value="[0-9][0-9][0-9][0-9][0-9]"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="popupposition">
}
}
+ void client_remove_destroy_notify_data(ObClientCallback func, gpointer data)
+ {
+ GSList *it;
+
+ for (it = client_destroy_notifies; it; it = g_slist_next(it)) {
+ ClientCallback *d = it->data;
+ if (d->func == func && d->data == data) {
+ g_slice_free(ClientCallback, d);
+ client_destroy_notifies =
+ g_slist_delete_link(client_destroy_notifies, it);
+ break;
+ }
+ }
+ }
+
void client_set_list(void)
{
Window *windows, *win_it;
Time launch_time;
guint32 user_time;
gboolean obplaced;
+ gulong ignore_start;
ob_debug("Managing window: 0x%lx", window);
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
ob_debug("Window name: %s class: %s role: %s title: %s",
self->name, self->class, self->role, self->title);
+ ob_debug("Window group name: %s group class: %s",
+ self->group_name, self->group_class);
/* per-app settings override stuff from client_get_all, and return the
settings for other uses too. the returned settings is a shallow copy,
"program + user specified" :
"BADNESS !?")))), place.width, place.height);
- obplaced = place_client(self, do_activate, &place.x, &place.y,
- settings);
+ obplaced = place_client(self, do_activate, &place, settings);
/* watch for buggy apps that ask to be placed at (0,0) when there is
a strut there */
/* grab mouse bindings before showing the window */
mouse_grab_for_client(self, TRUE);
+ if (!config_focus_under_mouse)
+ ignore_start = event_start_ignore_all_enters();
+
/* 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);
- }
+ client_show(self);
/* activate/hilight/raise the window */
if (try_activate) {
stacking_raise(CLIENT_AS_WINDOW(self));
}
+ if (!config_focus_under_mouse)
+ event_end_ignore_all_enters(ignore_start);
+
/* add to client list/map */
client_list = g_list_append(client_list, self);
window_add(&self->window, CLIENT_AS_WINDOW(self));
g_free(self->name);
g_free(self->class);
g_free(self->role);
+ g_free(self->group_name);
+ g_free(self->group_class);
g_free(self->client_machine);
g_free(self->sm_client_id);
g_slice_free(ObClient, self);
g_assert(app->name != NULL || app->class != NULL ||
app->role != NULL || app->title != NULL ||
+ app->group_name != NULL || app->group_class != NULL ||
(signed)app->type >= 0);
if (app->name &&
!g_pattern_match(app->name, strlen(self->name), self->name, NULL))
match = FALSE;
+ else if (app->group_name &&
+ !g_pattern_match(app->group_name,
+ strlen(self->group_name), self->group_name, NULL))
+ match = FALSE;
else if (app->class &&
!g_pattern_match(app->class,
strlen(self->class), self->class, NULL))
match = FALSE;
+ else if (app->group_class &&
+ !g_pattern_match(app->group_class,
+ strlen(self->group_class), self->group_class,
+ NULL))
+ match = FALSE;
else if (app->role &&
!g_pattern_match(app->role,
strlen(self->role), self->role, NULL))
self->desktop = settings->desktop - 1;
}
+ if (settings->opacity != -1)
+ self->opacity = settings->opacity;
+
if (settings->layer == -1) {
self->below = TRUE;
self->above = FALSE;
self->max_horz = self->session->max_horz;
self->max_vert = self->session->max_vert;
self->undecorated = self->session->undecorated;
+
+ self->opacity = self->session->opacity;
}
static gboolean client_restore_session_stacking(ObClient *self)
from per-app settings */
client_get_session_ids(self);
- /* now we got everything that can affect the decorations */
+ /* get this early so we have it for debugging, also this can be used
+ by app rule matching */
+ client_update_title(self);
+
+ /* now we got everything that can affect the decorations or app rule
+ matching */
if (!real)
return;
- /* get this early so we have it for debugging */
- client_update_title(self);
-
/* save the values of the variables used for app rule matching */
client_save_app_rule_values(self);
if (self->name == NULL) self->name = g_strdup("");
if (self->class == NULL) self->class = g_strdup("");
+ /* get the WM_CLASS (name and class) from the group leader. make them "" if
+ they are not provided */
+ if (leader)
+ got = OBT_PROP_GETSS_TYPE(leader, WM_CLASS, STRING_NO_CC, &ss);
+ else
+ got = FALSE;
+
+ if (got) {
+ if (ss[0]) {
+ self->group_name = g_strdup(ss[0]);
+ if (ss[1])
+ self->group_class = g_strdup(ss[1]);
+ }
+ g_strfreev(ss);
+ }
+
+ if (self->group_name == NULL) self->group_name = g_strdup("");
+ if (self->group_class == NULL) self->group_class = g_strdup("");
+
/* get the WM_WINDOW_ROLE. make it "" if it is not provided */
got = OBT_PROP_GETS_XPCS(self->window, WM_WINDOW_ROLE, &s);
OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
+ OBT_PROP_SETS(self->window, OB_APP_GROUP_NAME, self->group_name);
+ OBT_PROP_SETS(self->window, OB_APP_GROUP_CLASS, self->group_class);
OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
switch (self->type) {
self->type == OB_CLIENT_TYPE_TOOLBAR);
}
+ gboolean client_occupies_space(ObClient *self)
+ {
+ return !(self->type == OB_CLIENT_TYPE_DESKTOP ||
+ self->type == OB_CLIENT_TYPE_SPLASH);
+ }
+
gboolean client_mouse_focusable(ObClient *self)
{
return !(self->type == OB_CLIENT_TYPE_MENU ||
gboolean demands_attention = self->demands_attention;
gboolean max_horz = self->max_horz;
gboolean max_vert = self->max_vert;
+ guint8 opacity = self->opacity;
Rect oldarea;
gint l;
/* make sure client_setup_decor_and_functions() is called at least once */
client_setup_decor_and_functions(self, FALSE);
+ /* make the client semi-transparent */
+ client_set_opacity(self, opacity);
+
/* if the window hasn't been configured yet, then do so now, in fact the
x,y,w,h may _not_ be the same as the area rect, which can end up
meaning that the client isn't properly moved/resized by the fullscreen
focus_cycle_addremove(NULL, TRUE);
}
+void client_set_opacity(ObClient *self, guint8 opacity)
+{
+ OBT_PROP_SET32(self->window, NET_WM_WINDOW_OPACITY, CARDINAL,
+ opacity * 16777216);
+}
+
gboolean client_is_direct_child(ObClient *parent, ObClient *child)
{
while (child != parent && (child = client_direct_parent(child)));
gchar *class;
/*! The specified role of the window, used for identification */
gchar *role;
+ /*! The application that created the window's group. */
+ gchar *group_name;
+ /*! The class of the window's group, can used for grouping */
+ gchar *group_class;
/*! The session client id for the window. *This can be NULL!* */
gchar *sm_client_id;
gboolean max_vert;
/*! The window is maximized to fill the screen horizontally */
gboolean max_horz;
+ /*! The window is semi-transparent */
+ guint8 opacity;
/*! The window should not be displayed by pagers */
gboolean skip_pager;
/*! The window should not be displayed by taskbars */
/*! Get notified when the client is unmanaged */
void client_add_destroy_notify(ObClientCallback func, gpointer data);
void client_remove_destroy_notify(ObClientCallback func);
+ void client_remove_destroy_notify_data(ObClientCallback func, gpointer data);
/*! Manages a given window
@param prompt This specifies an ObPrompt which is being managed. It is
(utilty, menu, etc) */
gboolean client_helper(ObClient *self);
+ /*! Returns true if the window occupies space in the monitor conceptually, or
+ false if it does not and its presence should be ignored when possible. */
+ gboolean client_occupies_space(ObClient *self);
+
/*! Return if the client is a type which should be given focus from mouse
presses on the *client* window. This doesn't affect clicking on the
decorations. This doesn't count for focus cycling, different rules apply to
/*! Determine if the window, using the given client-area, would be considered
as an "oldschool fullscreen" window, that is, if it is filling a whole
monitor. */
- gboolean client_is_oldfullscreen(const ObClient const *self, const Rect *area);
+ gboolean client_is_oldfullscreen(const ObClient *self, const Rect *area);
/*! Iconifies or uniconifies the client window
@param iconic true if the window should be iconified; false if it should be
void client_set_desktop(ObClient *self, guint target, gboolean donthide,
gboolean dontraise);
+/*! Adjust the client opacity */
+void client_set_opacity(ObClient *self, guint8 opacity);
+
/*! Show the client if it should be shown. Returns if the window is shown. */
gboolean client_show(ObClient *self);
gboolean config_unfocus_leave;
ObPlacePolicy config_place_policy;
- gboolean config_place_center;
ObPlaceMonitor config_place_monitor;
guint config_primary_monitor_index;
gchar *config_theme;
gboolean config_theme_keepborder;
guint config_theme_window_list_icon_size;
+guint config_frame_flash_delay;
+guint config_frame_flash_duration;
gchar *config_title_layout;
settings->fullscreen = -1;
settings->max_horz = -1;
settings->max_vert = -1;
+ settings->opacity = -1;
return settings;
}
copy_if(fullscreen, -1);
copy_if(max_horz, -1);
copy_if(max_vert, -1);
+ copy_if(opacity, -1);
if (src->pos_given) {
dst->pos_given = TRUE;
dst->position = src->position;
/* monitor is copied above */
}
+
+ if (src->size_given) {
+ dst->size_given = TRUE;
+ dst->width_num = src->width_num;
+ dst->width_denom = src->width_denom;
+ dst->height_num = src->height_num;
+ dst->height_denom = src->height_denom;
+ }
}
void config_parse_relative_number(gchar *s, gint *num, gint *denom)
</applications>
*/
+ static void parse_single_per_app_settings(xmlNodePtr app,
+ ObAppSettings *settings)
+ {
+ xmlNodePtr n, c;
+ gboolean x_pos_given = FALSE;
+ gboolean width_given = FALSE;
+
+ if ((n = obt_xml_find_node(app->children, "decor")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->decor = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "shade")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->shade = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "position"))) {
+ if ((c = obt_xml_find_node(n->children, "x"))) {
+ if (!obt_xml_node_contains(c, "default")) {
+ config_parse_gravity_coord(c, &settings->position.x);
+ x_pos_given = TRUE;
+ }
+ }
+
+ if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
+ if (!obt_xml_node_contains(c, "default")) {
+ config_parse_gravity_coord(c, &settings->position.y);
+ settings->pos_given = TRUE;
+ }
+ }
+
+ /* monitor can be set without setting x or y */
+ if ((c = obt_xml_find_node(n->children, "monitor"))) {
+ if (!obt_xml_node_contains(c, "default")) {
+ gchar *s = obt_xml_node_string(c);
+ if (!g_ascii_strcasecmp(s, "mouse"))
+ settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
+ else if (!g_ascii_strcasecmp(s, "active"))
+ settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
+ else if (!g_ascii_strcasecmp(s, "primary"))
+ settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
+ else
+ settings->monitor = obt_xml_node_int(c);
+ g_free(s);
+ }
+ }
+
+ obt_xml_attr_bool(n, "force", &settings->pos_force);
+ }
+
+ if ((n = obt_xml_find_node(app->children, "size"))) {
+ if ((c = obt_xml_find_node(n->children, "width"))) {
+ if (!obt_xml_node_contains(c, "default")) {
+ gchar *s = obt_xml_node_string(c);
+ config_parse_relative_number(s,
+ &settings->width_num,
+ &settings->width_denom);
+ if (settings->width_num > 0 && settings->width_denom >= 0)
+ width_given = TRUE;
+ g_free(s);
+ }
+ }
+
+ if (width_given && (c = obt_xml_find_node(n->children, "height"))) {
+ gchar *s = obt_xml_node_string(c);
+ config_parse_relative_number(s,
+ &settings->height_num,
+ &settings->height_denom);
+ if (settings->height_num > 0 && settings->height_denom >= 0)
+ settings->size_given = TRUE;
+ g_free(s);
+ }
+ }
+
+ if ((n = obt_xml_find_node(app->children, "focus"))) {
+ if (!obt_xml_node_contains(n, "default"))
+ settings->focus = obt_xml_node_bool(n);
+ }
+
+ if ((n = obt_xml_find_node(app->children, "desktop"))) {
+ if (!obt_xml_node_contains(n, "default")) {
+ gchar *s = obt_xml_node_string(n);
+ if (!g_ascii_strcasecmp(s, "all"))
+ settings->desktop = DESKTOP_ALL;
+ else {
+ gint i = obt_xml_node_int(n);
+ if (i > 0)
+ settings->desktop = i;
+ }
+ g_free(s);
+ }
+ }
+
+ if ((n = obt_xml_find_node(app->children, "layer"))) {
+ if (!obt_xml_node_contains(n, "default")) {
+ gchar *s = obt_xml_node_string(n);
+ if (!g_ascii_strcasecmp(s, "above"))
+ settings->layer = 1;
+ else if (!g_ascii_strcasecmp(s, "below"))
+ settings->layer = -1;
+ else
+ settings->layer = 0;
+ g_free(s);
+ }
+ }
+
+ if ((n = obt_xml_find_node(app->children, "iconic")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->iconic = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "skip_pager")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->skip_pager = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->skip_taskbar = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "fullscreen")))
+ if (!obt_xml_node_contains(n, "default"))
+ settings->fullscreen = obt_xml_node_bool(n);
+
+ if ((n = obt_xml_find_node(app->children, "maximized"))) {
+ if (!obt_xml_node_contains(n, "default")) {
+ gchar *s = obt_xml_node_string(n);
+ if (!g_ascii_strcasecmp(s, "horizontal")) {
+ settings->max_horz = TRUE;
+ settings->max_vert = FALSE;
+ } else if (!g_ascii_strcasecmp(s, "vertical")) {
+ settings->max_horz = FALSE;
+ settings->max_vert = TRUE;
+ } else
+ settings->max_horz = settings->max_vert =
+ obt_xml_node_bool(n);
+ g_free(s);
+ }
+ }
++
++ if ((n = obt_xml_find_node(app->children, "opacity")))
++ if (!obt_xml_node_contains(n, "default"))
++ settings->opacity = obt_xml_node_int(n);
+ }
+
/* Manages settings for individual applications.
Some notes: monitor is the screen number in a multi monitor
(Xinerama) setup (starting from 0), or mouse: the monitor the pointer
static void parse_per_app_settings(xmlNodePtr node, gpointer d)
{
xmlNodePtr app = obt_xml_find_node(node->children, "application");
- gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
- *type_str = NULL;
- gboolean name_set, class_set, type_set, role_set, title_set;
- ObClientType type;
- gboolean x_pos_given;
+ for (; app; app = obt_xml_find_node(app->next, "application")) {
+ ObAppSettings *settings;
- while (app) {
- x_pos_given = FALSE;
+ gboolean name_set, class_set, role_set, title_set,
+ type_set, group_name_set, group_class_set;
+ gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
+ *type_str = NULL, *group_name = NULL, *group_class = NULL;
+ ObClientType type;
class_set = obt_xml_attr_string(app, "class", &class);
name_set = obt_xml_attr_string(app, "name", &name);
+ group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
+ group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
type_set = obt_xml_attr_string(app, "type", &type_str);
role_set = obt_xml_attr_string(app, "role", &role);
title_set = obt_xml_attr_string(app, "title", &title);
type_set = FALSE; /* not valid! */
}
- if (class_set || name_set || role_set || title_set || type_set) {
- xmlNodePtr n, c;
- ObAppSettings *settings = config_create_app_settings();
-
- if (name_set)
- settings->name = g_pattern_spec_new(name);
-
- if (class_set)
- settings->class = g_pattern_spec_new(class);
-
- if (role_set)
- settings->role = g_pattern_spec_new(role);
-
- if (title_set)
- settings->title = g_pattern_spec_new(title);
-
- if (type_set)
- settings->type = type;
-
- if ((n = obt_xml_find_node(app->children, "decor")))
- if (!obt_xml_node_contains(n, "default"))
- settings->decor = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "shade")))
- if (!obt_xml_node_contains(n, "default"))
- settings->shade = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "position"))) {
- if ((c = obt_xml_find_node(n->children, "x")))
- if (!obt_xml_node_contains(c, "default")) {
- config_parse_gravity_coord(c, &settings->position.x);
- x_pos_given = TRUE;
- }
-
- if (x_pos_given && (c = obt_xml_find_node(n->children, "y")))
- if (!obt_xml_node_contains(c, "default")) {
- config_parse_gravity_coord(c, &settings->position.y);
- settings->pos_given = TRUE;
- }
-
- /* monitor can be set without setting x or y */
- if ((c = obt_xml_find_node(n->children, "monitor")))
- if (!obt_xml_node_contains(c, "default")) {
- gchar *s = obt_xml_node_string(c);
- if (!g_ascii_strcasecmp(s, "mouse"))
- settings->monitor_type =
- OB_PLACE_MONITOR_MOUSE;
- else if (!g_ascii_strcasecmp(s, "active"))
- settings->monitor_type =
- OB_PLACE_MONITOR_ACTIVE;
- else if (!g_ascii_strcasecmp(s, "primary"))
- settings->monitor_type =
- OB_PLACE_MONITOR_PRIMARY;
- else
- settings->monitor = obt_xml_node_int(c);
- g_free(s);
- }
-
- obt_xml_attr_bool(n, "force", &settings->pos_force);
- }
-
- if ((n = obt_xml_find_node(app->children, "focus")))
- if (!obt_xml_node_contains(n, "default"))
- settings->focus = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "desktop"))) {
- if (!obt_xml_node_contains(n, "default")) {
- gchar *s = obt_xml_node_string(n);
- if (!g_ascii_strcasecmp(s, "all"))
- settings->desktop = DESKTOP_ALL;
- else {
- gint i = obt_xml_node_int(n);
- if (i > 0)
- settings->desktop = i;
- }
- g_free(s);
- }
- }
+ if (!(class_set || name_set || role_set || title_set ||
+ type_set || group_class_set || group_name_set))
+ continue;
+
+ settings = config_create_app_settings();
+
+ if (name_set)
+ settings->name = g_pattern_spec_new(name);
+ if (class_set)
+ settings->class = g_pattern_spec_new(class);
+ if (group_name_set)
+ settings->group_name = g_pattern_spec_new(group_name);
+ if (group_class_set)
+ settings->group_class = g_pattern_spec_new(group_class);
+ if (role_set)
+ settings->role = g_pattern_spec_new(role);
+ if (title_set)
+ settings->title = g_pattern_spec_new(title);
+ if (type_set)
+ settings->type = type;
- if ((n = obt_xml_find_node(app->children, "layer")))
- if (!obt_xml_node_contains(n, "default")) {
- gchar *s = obt_xml_node_string(n);
- if (!g_ascii_strcasecmp(s, "above"))
- settings->layer = 1;
- else if (!g_ascii_strcasecmp(s, "below"))
- settings->layer = -1;
- else
- settings->layer = 0;
- g_free(s);
- }
-
- if ((n = obt_xml_find_node(app->children, "iconic")))
- if (!obt_xml_node_contains(n, "default"))
- settings->iconic = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "skip_pager")))
- if (!obt_xml_node_contains(n, "default"))
- settings->skip_pager = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
- if (!obt_xml_node_contains(n, "default"))
- settings->skip_taskbar = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "fullscreen")))
- if (!obt_xml_node_contains(n, "default"))
- settings->fullscreen = obt_xml_node_bool(n);
-
- if ((n = obt_xml_find_node(app->children, "maximized")))
- if (!obt_xml_node_contains(n, "default")) {
- gchar *s = obt_xml_node_string(n);
- if (!g_ascii_strcasecmp(s, "horizontal")) {
- settings->max_horz = TRUE;
- settings->max_vert = FALSE;
- } else if (!g_ascii_strcasecmp(s, "vertical")) {
- settings->max_horz = FALSE;
- settings->max_vert = TRUE;
- } else
- settings->max_horz = settings->max_vert =
- obt_xml_node_bool(n);
- g_free(s);
- }
-
- if ((n = obt_xml_find_node(app->children, "opacity")))
- if (!obt_xml_node_contains(n, "default"))
- settings->opacity = obt_xml_node_int(n);
-
- config_per_app_settings = g_slist_append(config_per_app_settings,
- (gpointer) settings);
- g_free(name);
- g_free(class);
- g_free(role);
- g_free(title);
- g_free(type_str);
- name = class = role = title = type_str = NULL;
- }
-
- app = obt_xml_find_node(app->next, "application");
+ g_free(name);
+ g_free(class);
+ g_free(group_name);
+ g_free(group_class);
+ g_free(role);
+ g_free(title);
+ g_free(type_str);
+
+ parse_single_per_app_settings(app, settings);
+ config_per_app_settings = g_slist_append(config_per_app_settings,
+ (gpointer)settings);
}
}
if ((n = obt_xml_find_node(node, "policy")))
if (obt_xml_node_contains(n, "UnderMouse"))
config_place_policy = OB_PLACE_POLICY_MOUSE;
- if ((n = obt_xml_find_node(node, "center")))
- config_place_center = obt_xml_node_bool(n);
if ((n = obt_xml_find_node(node, "monitor"))) {
if (obt_xml_node_contains(n, "active"))
config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
else if (config_theme_window_list_icon_size > 96)
config_theme_window_list_icon_size = 96;
}
+ if ((n = obt_xml_find_node(node, "flashFrameDelay")))
+ config_frame_flash_delay = obt_xml_node_int(n);
+ if ((n = obt_xml_find_node(node, "flashFrameDuration")))
+ config_frame_flash_duration = obt_xml_node_int(n);
n = obt_xml_find_node(node, "font");
while (n) {
obt_xml_register(i, "focus", parse_focus, NULL);
config_place_policy = OB_PLACE_POLICY_SMART;
- config_place_center = TRUE;
config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
config_primary_monitor_index = 1;
config_title_layout = g_strdup("NLIMC");
config_theme_keepborder = TRUE;
config_theme_window_list_icon_size = 36;
+ config_frame_flash_delay = 600;
+ config_frame_flash_duration = 5000;
config_font_activewindow = NULL;
config_font_inactivewindow = NULL;
for (it = config_per_app_settings; it; it = g_slist_next(it)) {
ObAppSettings *itd = (ObAppSettings *)it->data;
- if (itd->name) g_pattern_spec_free(itd->name);
- if (itd->role) g_pattern_spec_free(itd->role);
+ if (itd->name) g_pattern_spec_free(itd->name);
+ if (itd->role) g_pattern_spec_free(itd->role);
if (itd->title) g_pattern_spec_free(itd->title);
if (itd->class) g_pattern_spec_free(itd->class);
+ if (itd->group_name) g_pattern_spec_free(itd->group_name);
+ if (itd->group_class) g_pattern_spec_free(itd->group_class);
g_slice_free(ObAppSettings, it->data);
}
g_slist_free(config_per_app_settings);
GPatternSpec *class;
GPatternSpec *name;
GPatternSpec *role;
+ GPatternSpec *group_class;
+ GPatternSpec *group_name;
GPatternSpec *title;
ObClientType type;
gboolean pos_given;
gboolean pos_force;
+ gint width_num;
+ gint width_denom;
+ gint height_num;
+ gint height_denom;
+ gboolean size_given;
+
guint desktop;
gint shade;
gint decor;
gint max_horz;
gint max_vert;
gint fullscreen;
-
gint layer;
+
+ guint8 opacity;
};
/*! Should new windows be focused */
/*! The algorithm to use for placing new windows */
extern ObPlacePolicy config_place_policy;
- /*! Place windows in the center of the free area */
- extern gboolean config_place_center;
/*! Place windows on the active monitor (unless they are part of an application
already on another monitor) */
extern ObPlaceMonitor config_place_monitor;
extern gboolean config_animate_iconify;
/*! Size of icons in focus switching dialogs */
extern guint config_theme_window_list_icon_size;
+/*! Amount of time between flashes (0 to disable flashing) */
+extern guint config_frame_flash_delay;
+/*! How long (ms) to flash the window's frame (0 to flash forever) */
+extern guint config_frame_flash_duration;
/*! The font for the active window's title */
extern RrFont *config_font_activewindow;
STRUT_SET(self->size,
self->cbwidth_l + (!self->max_horz ? self->bwidth : 0),
- self->cbwidth_t + self->bwidth,
+ self->cbwidth_t +
+ (!self->max_horz || !self->max_vert ? self->bwidth : 0),
self->cbwidth_r + (!self->max_horz ? self->bwidth : 0),
self->cbwidth_b +
(!self->max_horz || !self->max_vert ? self->bwidth : 0));
if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
self->size.top += ob_rr_theme->title_height + self->bwidth;
+ else if (self->max_horz && self->max_vert) {
+ /* A maximized and undecorated window needs a small border on the
+ top of the window to let the user still undecorate/unmaximize the
+ window via the client menu. */
+ /* XXX This size should probably be a theme option. */
+ self->size.top += 1;
+ }
+
if (self->decorations & OB_FRAME_DECOR_HANDLE &&
ob_rr_theme->handle_height > 0)
{
ObFrame *self = data;
GTimeVal now;
- g_get_current_time(&now);
- if (now.tv_sec > self->flash_end.tv_sec ||
- (now.tv_sec == self->flash_end.tv_sec &&
- now.tv_usec >= self->flash_end.tv_usec))
- self->flashing = FALSE;
+ if (config_frame_flash_duration != 0) {
+ g_get_current_time(&now);
+ if (now.tv_sec > self->flash_end.tv_sec ||
+ (now.tv_sec == self->flash_end.tv_sec &&
+ now.tv_usec >= self->flash_end.tv_usec))
+ self->flashing = FALSE;
+ }
if (!self->flashing)
return FALSE; /* we are done */
void frame_flash_start(ObFrame *self)
{
+ if (config_frame_flash_delay == 0) return;
+
self->flash_on = self->focused;
if (!self->flashing)
self->flash_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
- 600, flash_timeout, self,
+ config_frame_flash_delay, flash_timeout, self,
flash_done);
- g_get_current_time(&self->flash_end);
- g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
+
+ if (config_frame_flash_duration != 0) {
+ g_get_current_time(&self->flash_end);
+ g_time_val_add(&self->flash_end, 1000 * config_frame_flash_duration);
+ }
self->flashing = TRUE;
}
switch (edge_warp_dir) {
case OB_DIRECTION_NORTH:
- y = a->height - 1;
+ y = a->height - 2;
break;
case OB_DIRECTION_EAST:
- x = a->x;
+ x = a->x + 1;
break;
case OB_DIRECTION_SOUTH:
- y = a->y;
+ y = a->y + 1;
break;
case OB_DIRECTION_WEST:
- x = a->width - 1;
+ x = a->width - 2;
break;
default:
g_assert_not_reached();
for (i = 0; i < screen_num_monitors; ++i) {
const Rect *a = screen_physical_area_monitor(i);
+
+ if (!RECT_CONTAINS(*a, x, y))
+ continue;
+
if (x == RECT_LEFT(*a)) dir = OB_DIRECTION_WEST;
if (x == RECT_RIGHT(*a)) dir = OB_DIRECTION_EAST;
if (y == RECT_TOP(*a)) dir = OB_DIRECTION_NORTH;