+/* -*- 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.
+*/
+
#include "client.h"
#include "debug.h"
#include "startupnotify.h"
}
}
XFree(children);
-
- if (config_focus_new)
- focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
}
void client_manage(Window window)
client_restore_session_stacking(self);
/* focus the new window? */
- if (ob_state() != OB_STATE_STARTING && config_focus_new &&
+ if (ob_state() != OB_STATE_STARTING &&
+ (config_focus_new || (self->transient_for &&
+ self->transient_for != OB_TRAN_GROUP &&
+ client_focused(self->transient_for))) &&
/* note the check against Type_Normal/Dialog, not client_normal(self),
which would also include other types. in this case we want more
strict rules for focus */
g_free(self->name);
g_free(self->class);
g_free(self->role);
+ g_free(self->sm_client_id);
g_free(self);
/* update the list hints */
/* XXX watch for xinerama dead areas */
a = screen_area(self->desktop);
- 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 (client_normal(self)) {
+ 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.
client_get_state(self);
client_get_shaped(self);
- g_message("self->iconic %d", self->iconic);
-
client_get_mwm_hints(self);
client_get_type(self);/* this can change the mwmhints for special cases */
client_update_title(self);
client_update_class(self);
+ client_update_sm_client_id(self);
client_update_strut(self);
client_update_icons(self);
}
GList *it;
guint32 nums;
guint i;
- char *data = NULL;
+ gchar *data = NULL;
gboolean read_title;
+ gchar *old_title;
- g_free(self->title);
+ old_title = self->title;
/* try netwm */
if (!PROP_GETS(self->window, net_wm_name, utf8, &data))
if (!PROP_GETS(self->window, wm_name, locale, &data))
data = g_strdup("Unnamed Window");
+ /* did the title change? then reset the title_count */
+ if (old_title && 0 != strncmp(old_title, data, strlen(data)))
+ self->title_count = 1;
+
/* look for duplicates and append a number */
nums = 0;
for (it = client_list; it; it = it->next)
char *ndata;
ndata = g_strdup_printf("%s - [%u]", data, self->title_count);
g_free(data);
- data = vdata;
+ data = ndata;
}
PROP_SETS(self->window, net_wm_visible_name, data);
if (self->frame)
frame_adjust_title(self->frame);
+ g_free(old_title);
+
/* update the icon title */
data = NULL;
g_free(self->icon_title);
}
if (PROP_GETS(self->window, wm_window_role, locale, &s))
- self->role = g_strdup(s);
+ self->role = s;
if (self->name == NULL) self->name = g_strdup("");
if (self->class == NULL) self->class = g_strdup("");
}
}
+ if (!self->nicons) {
+ self->nicons++;
+ self->icons = g_new(ObClientIcon, self->nicons);
+ self->icons[self->nicons-1].width = 48;
+ self->icons[self->nicons-1].height = 48;
+ self->icons[self->nicons-1].data = g_memdup(ob_rr_theme->def_win_icon,
+ sizeof(RrPixel32)
+ * 48 * 48);
+ }
+
if (self->frame)
frame_adjust_icon(self->frame);
}
{
/* these are in a carefully crafted order.. */
- g_message("self->iconic %d", self->iconic);
if (self->iconic) {
self->iconic = FALSE;
client_iconify(self, TRUE, FALSE);
gboolean user, gboolean final,
gboolean force_reply)
{
+ gint oldw, oldh;
+ gboolean send_resize_client;
gboolean moved = FALSE, resized = FALSE;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
moved = x != self->area.x || y != self->area.y;
resized = w != self->area.width || h != self->area.height;
+ oldw = self->area.width;
+ oldh = self->area.height;
RECT_SET(self->area, x, y, w, h);
/* for app-requested resizes, always resize if 'resized' is true.
for user-requested ones, only resize if final is true, or when
resizing in redraw mode */
- if ((!user && resized) ||
- (user && (final || (resized && config_redraw_resize))))
- XResizeWindow(ob_display, self->window, w, h);
+ send_resize_client = ((!user && resized) ||
+ (user && (final ||
+ (resized && config_redraw_resize))));
+
+ /* if the client is enlarging, the 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));
/* move/resize the frame to match the request */
if (self->frame) {
event.xconfigure.override_redirect = FALSE;
XSendEvent(event.xconfigure.display, event.xconfigure.window,
FALSE, StructureNotifyMask, &event);
- }
+ }
}
+
+ /* if the client is shrinking, then resize the frame before the client */
+ if (send_resize_client && (!user || (w <= oldw || h <= oldh)))
+ XResizeWindow(ob_display, self->window, w, h);
+
+ XFlush(ob_display);
}
void client_fullscreen(ObClient *self, gboolean fs, gboolean savearea)
and adjust out layer/stacking */
if (fs) {
- if (savearea) {
- guint32 dimensions[4];
- dimensions[0] = self->area.x;
- dimensions[1] = self->area.y;
- dimensions[2] = self->area.width;
- dimensions[3] = self->area.height;
-
- PROP_SETA32(self->window, openbox_premax, cardinal,
- dimensions, 4);
- }
+ if (savearea)
+ self->pre_fullscreen_area = self->area;
/* these are not actually used cuz client_configure will set them
as appropriate when the window is fullscreened */
x = y = w = h = 0;
} else {
- guint num;
- gint32 *dimensions;
Rect *a;
- /* pick some fallbacks... */
- a = screen_area_monitor(self->desktop, 0);
- x = a->x + a->width / 4;
- y = a->y + a->height / 4;
- w = a->width / 2;
- h = a->height / 2;
-
- if (PROP_GETA32(self->window, openbox_premax, cardinal,
- (guint32**)&dimensions, &num)) {
- if (num == 4) {
- x = dimensions[0];
- y = dimensions[1];
- w = dimensions[2];
- h = dimensions[3];
- }
- g_free(dimensions);
- }
+ if (self->pre_fullscreen_area.width > 0 &&
+ self->pre_fullscreen_area.height > 0)
+ {
+ x = self->pre_fullscreen_area.x;
+ y = self->pre_fullscreen_area.y;
+ w = self->pre_fullscreen_area.width;
+ h = self->pre_fullscreen_area.height;
+ RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0);
+ } else {
+ /* pick some fallbacks... */
+ a = screen_area_monitor(self->desktop, 0);
+ x = a->x + a->width / 4;
+ y = a->y + a->height / 4;
+ w = a->width / 2;
+ h = a->height / 2;
+ }
}
client_setup_decor_and_functions(self);
if (iconic) {
if (self->functions & OB_CLIENT_FUNC_ICONIFY) {
+ long old;
+
+ old = self->wmstate;
self->wmstate = IconicState;
+ if (old != self->wmstate)
+ PROP_MSG(self->window, kde_wm_change_state,
+ self->wmstate, 1, 0, 0);
+
self->ignore_unmaps++;
/* we unmap the client itself so that we can get MapRequest
events, and because the ICCCM tells us to! */
changed = TRUE;
}
} else {
+ long old;
+
if (curdesk)
client_set_desktop(self, screen_desktop, FALSE);
+
+ old = self->wmstate;
self->wmstate = self->shaded ? IconicState : NormalState;
+ if (old != self->wmstate)
+ PROP_MSG(self->window, kde_wm_change_state,
+ self->wmstate, 1, 0, 0);
+
XMapWindow(ob_display, self->window);
/* this puts it after the current focused window */
/* check if already done */
if (max) {
- if (dir == 0 && self->max_horz && self->max_vert) return;
- if (dir == 1 && self->max_horz) return;
- if (dir == 2 && self->max_vert) return;
+ if (dir == 0 && self->max_horz && self->max_vert) return;
+ if (dir == 1 && self->max_horz) return;
+ if (dir == 2 && self->max_vert) return;
} else {
- if (dir == 0 && !self->max_horz && !self->max_vert) return;
- if (dir == 1 && !self->max_horz) return;
- if (dir == 2 && !self->max_vert) return;
+ if (dir == 0 && !self->max_horz && !self->max_vert) return;
+ if (dir == 1 && !self->max_horz) return;
+ if (dir == 2 && !self->max_vert) return;
}
- /* work with the frame's coords */
- x = self->frame->area.x;
- y = self->frame->area.y;
+ /* we just tell it to configure in the same place and client_configure
+ worries about filling the screen with the window */
+ x = self->area.x;
+ y = self->area.y;
w = self->area.width;
h = self->area.height;
if (max) {
- if (savearea) {
- gint32 dimensions[4];
- gint32 *readdim;
- guint num;
-
- dimensions[0] = x;
- dimensions[1] = y;
- dimensions[2] = w;
- dimensions[3] = h;
-
- /* get the property off the window and use it for the dimensions
- we are already maxed on */
- if (PROP_GETA32(self->window, openbox_premax, cardinal,
- (guint32**)&readdim, &num)) {
- if (num == 4) {
- if (self->max_horz) {
- dimensions[0] = readdim[0];
- dimensions[2] = readdim[2];
- }
- if (self->max_vert) {
- dimensions[1] = readdim[1];
- dimensions[3] = readdim[3];
- }
- }
- g_free(readdim);
- }
-
- PROP_SETA32(self->window, openbox_premax, cardinal,
- (guint32*)dimensions, 4);
- }
+ if (savearea)
+ self->pre_max_area = self->area;
} else {
- guint num;
- gint32 *dimensions;
Rect *a;
- /* pick some fallbacks... */
a = screen_area_monitor(self->desktop, 0);
- if (dir == 0 || dir == 1) { /* horz */
- x = a->x + a->width / 4;
- w = a->width / 2;
- }
- if (dir == 0 || dir == 2) { /* vert */
- y = a->y + a->height / 4;
- h = a->height / 2;
+ if ((dir == 0 || dir == 1) && self->max_horz) { /* horz */
+ if (self->pre_max_area.width > 0) {
+ x = self->pre_max_area.x;
+ w = self->pre_max_area.width;
+
+ RECT_SET(self->pre_max_area, 0, self->pre_max_area.y,
+ 0, self->pre_max_area.height);
+ } else {
+ /* pick some fallbacks... */
+ x = a->x + a->width / 4;
+ w = a->width / 2;
+ }
}
+ if ((dir == 0 || dir == 2) && self->max_vert) { /* vert */
+ if (self->pre_max_area.width > 0) {
+ y = self->pre_max_area.y;
+ h = self->pre_max_area.height;
- if (PROP_GETA32(self->window, openbox_premax, cardinal,
- (guint32**)&dimensions, &num)) {
- if (num == 4) {
- if (dir == 0 || dir == 1) { /* horz */
- x = dimensions[0];
- w = dimensions[2];
- }
- if (dir == 0 || dir == 2) { /* vert */
- y = dimensions[1];
- h = dimensions[3];
- }
+ RECT_SET(self->pre_max_area, self->pre_max_area.x, 0,
+ self->pre_max_area.width, 0);
+ } else {
+ /* pick some fallbacks... */
+ y = a->y + a->height / 4;
+ h = a->height / 2;
}
- g_free(dimensions);
- }
+ }
}
if (dir == 0 || dir == 1) /* horz */
- self->max_horz = max;
+ self->max_horz = max;
if (dir == 0 || dir == 2) /* vert */
- self->max_vert = max;
-
- if (!self->max_horz && !self->max_vert)
- PROP_ERASE(self->window, openbox_premax);
+ self->max_vert = max;
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_move_resize(self, x, y, w, h);
}
self->shaded == shade) return; /* already done */
/* when we're iconic, don't change the wmstate */
- if (!self->iconic)
- self->wmstate = shade ? IconicState : NormalState;
+ if (!self->iconic) {
+ long old;
+
+ old = self->wmstate;
+ self->wmstate = shade ? IconicState : NormalState;
+ if (old != self->wmstate)
+ PROP_MSG(self->window, kde_wm_change_state,
+ self->wmstate, 1, 0, 0);
+ }
+
self->shaded = shade;
client_change_state(self);
/* resize the frame to just the titlebar */
void client_unfocus(ObClient *self)
{
- g_assert(focus_client == self);
+ if (focus_client == self) {
#ifdef DEBUG_FOCUS
- ob_debug("client_unfocus for %lx\n", self->window);
+ ob_debug("client_unfocus for %lx\n", self->window);
#endif
- focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
+ focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
+ }
}
void client_activate(ObClient *self, gboolean here)
/* li is the largest image < req */
unsigned long size, smallest = 0xffffffff, largest = 0, si = 0, li = 0;
- if (!self->nicons) return NULL;
-
for (i = 0; i < self->nicons; ++i) {
size = self->icons[i].width * self->icons[i].height;
if (size < smallest && size >= (unsigned)(w * h)) {
return NULL;
}
-gchar* client_get_sm_client_id(ObClient *self)
+void client_update_sm_client_id(ObClient *self)
{
- gchar *id = NULL;
+ g_free(self->sm_client_id);
+ self->sm_client_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;
+ if (!PROP_GETS(self->window, sm_client_id, locale, &self->sm_client_id) &&
+ self->group)
+ PROP_GETS(self->group->leader, sm_client_id, locale,
+ &self->sm_client_id);
}
/* finds the nearest edge in the given direction from the current client
case OB_DIRECTION_NORTHWEST:
case OB_DIRECTION_SOUTHWEST:
/* not implemented */
- break;
default:
- g_assert_not_reached();
+ g_assert_not_reached();
}
return dest;
}
+
+ObClient* client_under_pointer()
+{
+ int x, y;
+ GList *it;
+ ObClient *ret = NULL;
+
+ if (screen_pointer_pos(&x, &y)) {
+ for (it = stacking_list; it != NULL; it = it->next) {
+ if (WINDOW_IS_CLIENT(it->data)) {
+ ObClient *c = WINDOW_AS_CLIENT(it->data);
+ if (c->desktop == screen_desktop &&
+ RECT_CONTAINS(c->frame->area, x, y)) {
+ ret = c;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}