- Themes
John McKnight (jmcknight@gmail.com)
- Clearlooks Themes
+David Barr (david@chalkskeletons.com)
+ - Bear2 Theme
+ _NET_WM_FULL_PLACEMENT (1.4)
+ _NET_WM_MOVERESIZE_CANCEL (1.4)
+ _NET_REQUEST_FRAME_EXTENTS (1.3)
++ _NET_WM_ACTION_MOVE (1.3)
++ _NET_WM_ACTION_RESIZE (1.3)
++ _NET_WM_ACTION_MINIMIZE (1.3)
++ _NET_WM_ACTION_SHADE (1.3)
+- _NET_WM_ACTION_STICK (1.3)
+ Openbox does not do large desktops, so no sticky state is needed.
++ _NET_WM_ACTION_MAXIMIZE_HORZ (1.3)
++ _NET_WM_ACTION_MAXIMIZE_VERT (1.3)
++ _NET_WM_ACTION_FULLSCREEN (1.3)
++ _NET_WM_ACTION_CHANGE_DESKTOP (1.3)
++ _NET_WM_ACTION_CLOSE (1.3)
++ _NET_WM_ACTION_ABOVE (1.4?)
++ _NET_WM_ACTION_BELOW (1.4?)
GList *client_list = NULL;
-static GSList *client_destructors = NULL;
+static GSList *client_destroy_notifies = NULL;
+static GSList *client_hide_notifies = NULL;
static void client_get_all(ObClient *self, gboolean real);
static void client_toggle_border(ObClient *self, gboolean show);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
-static void client_apply_startup_state(ObClient *self, gint x, gint y);
+static void client_apply_startup_state(ObClient *self);
static void client_restore_session_state(ObClient *self);
static gboolean client_restore_session_stacking(ObClient *self);
static ObAppSettings *client_get_settings_state(ObClient *self);
static GSList *client_search_all_top_parents_internal(ObClient *self,
gboolean bylayer,
ObStackingLayer layer);
+static void client_call_notifies(ObClient *self, GSList *list);
void client_startup(gboolean reconfig)
{
if (reconfig) return;
}
-void client_add_destructor(ObClientCallback func, gpointer data)
+static void client_call_notifies(ObClient *self, GSList *list)
+{
+ GSList *it;
+
+ for (it = list; it; it = g_slist_next(it)) {
+ ClientCallback *d = it->data;
+ d->func(self, d->data);
+ }
+}
+
+void client_add_destroy_notify(ObClientCallback func, gpointer data)
+{
+ ClientCallback *d = g_new(ClientCallback, 1);
+ d->func = func;
+ d->data = data;
+ client_destroy_notifies = g_slist_prepend(client_destroy_notifies, d);
+}
+
+void client_remove_destroy_notify(ObClientCallback func)
+{
+ GSList *it;
+
+ for (it = client_destroy_notifies; it; it = g_slist_next(it)) {
+ ClientCallback *d = it->data;
+ if (d->func == func) {
+ g_free(d);
+ client_destroy_notifies =
+ g_slist_delete_link(client_destroy_notifies, it);
+ break;
+ }
+ }
+}
+
+void client_add_hide_notify(ObClientCallback func, gpointer data)
{
ClientCallback *d = g_new(ClientCallback, 1);
d->func = func;
d->data = data;
- client_destructors = g_slist_prepend(client_destructors, d);
+ client_hide_notifies = g_slist_prepend(client_hide_notifies, d);
}
-void client_remove_destructor(ObClientCallback func)
+void client_remove_hide_notify(ObClientCallback func)
{
GSList *it;
- for (it = client_destructors; it; it = g_slist_next(it)) {
+ for (it = client_hide_notifies; it; it = g_slist_next(it)) {
ClientCallback *d = it->data;
if (d->func == func) {
g_free(d);
- client_destructors = g_slist_delete_link(client_destructors, it);
+ client_hide_notifies =
+ g_slist_delete_link(client_hide_notifies, it);
break;
}
}
XWMHints *wmhint;
gboolean activate = FALSE;
ObAppSettings *settings;
- gint newx, newy;
grab_server(TRUE);
activate = TRUE;
}
- /* get the current position */
- newx = self->area.x;
- newy = self->area.y;
-
/* figure out placement for the window */
if (ob_state() == OB_STATE_RUNNING) {
gboolean transient;
- transient = place_client(self, &newx, &newy, settings);
+ ob_debug("Positioned: %s @ %d %d\n",
+ (!self->positioned ? "no" :
+ (self->positioned == PPosition ? "program specified" :
+ (self->positioned == USPosition ? "user specified" :
+ "BADNESS !?"))), self->area.x, self->area.y);
+
+ transient = place_client(self, &self->area.x, &self->area.y, settings);
/* make sure the window is visible. */
- client_find_onscreen(self, &newx, &newy,
- self->area.width,
- self->area.height,
+ client_find_onscreen(self, &self->area.x, &self->area.y,
+ self->area.width, self->area.height,
/* non-normal clients has less rules, and
windows that are being restored from a
session do also. we can assume you want
also, this moves the window to the position where it has been placed
*/
ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
- self->window, newx, newy, self->area.width, self->area.height);
+ self->window, self->area.x, self->area.y,
+ self->area.width, self->area.height);
if (self->session)
- ob_debug("session requested %d %d\n",
+ ob_debug(" but session requested %d %d instead, overriding\n",
self->session->x, self->session->y);
- client_apply_startup_state(self, newx, newy);
+ /* generate a ConfigureNotify telling the client where it is */
+ client_configure_full(self, self->area.x, self->area.y,
+ self->area.width, self->area.height,
+ FALSE, TRUE);
+
+ client_apply_startup_state(self);
mouse_grab_for_client(self, TRUE);
/* adjust the frame to the client's size before showing the window */
frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+ frame_adjust_client_area(self->frame);
/* 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
if (STRUT_EXISTS(self->strut))
screen_update_areas();
- for (it = client_destructors; it; it = g_slist_next(it)) {
- ClientCallback *d = it->data;
- d->func(self, d->data);
- }
+ client_call_notifies(self, client_destroy_notifies);
/* tell our parent(s) that we're gone */
if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
OB_CLIENT_FUNC_ICONIFY |
OB_CLIENT_FUNC_MAXIMIZE |
OB_CLIENT_FUNC_SHADE |
- OB_CLIENT_FUNC_CLOSE);
+ OB_CLIENT_FUNC_CLOSE |
+ OB_CLIENT_FUNC_BELOW |
+ OB_CLIENT_FUNC_ABOVE);
if (!(self->min_size.width < self->max_size.width ||
self->min_size.height < self->max_size.height))
self->functions = OB_CLIENT_FUNC_MOVE;
case OB_CLIENT_TYPE_DESKTOP:
- case OB_CLIENT_TYPE_DOCK:
/* these windows are not manipulated by the window manager */
self->decorations = 0;
self->functions = 0;
+
+ case OB_CLIENT_TYPE_DOCK:
+ /* these windows are not manipulated by the window manager, but they
+ can set below layer which has a special meaning */
+ self->decorations = 0;
+ self->functions = OB_CLIENT_FUNC_BELOW;
break;
}
static void client_change_allowed_actions(ObClient *self)
{
- gulong actions[9];
+ gulong actions[11];
gint num = 0;
/* desktop windows are kept on all desktops */
actions[num++] = prop_atoms.net_wm_action_maximize_horz;
actions[num++] = prop_atoms.net_wm_action_maximize_vert;
}
+ if (self->functions & OB_CLIENT_FUNC_ABOVE)
+ actions[num++] = prop_atoms.net_wm_action_above;
+ if (self->functions & OB_CLIENT_FUNC_BELOW)
+ actions[num++] = prop_atoms.net_wm_action_below;
PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
{
if (!client_should_show(self)) {
frame_hide(self->frame);
+
+ client_call_notifies(self, client_hide_notifies);
}
/* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
}
else {
frame_hide(self->frame);
+
+ client_call_notifies(self, client_hide_notifies);
}
/* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
}
-static void client_apply_startup_state(ObClient *self, gint x, gint y)
+static void client_apply_startup_state(ObClient *self)
{
- gboolean pos = FALSE; /* has the window's position been configured? */
- gint ox, oy;
-
- /* save the position, and set self->area for these to use */
- ox = self->area.x;
- oy = self->area.y;
- self->area.x = x;
- self->area.y = y;
-
/* set the desktop hint, to make sure that it always exists */
PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
if (self->fullscreen) {
self->fullscreen = FALSE;
client_fullscreen(self, TRUE);
- pos = TRUE;
}
if (self->undecorated) {
self->undecorated = FALSE;
if (self->max_vert && self->max_horz) {
self->max_vert = self->max_horz = FALSE;
client_maximize(self, TRUE, 0);
- pos = TRUE;
} else if (self->max_vert) {
self->max_vert = FALSE;
client_maximize(self, TRUE, 2);
- pos = TRUE;
} else if (self->max_horz) {
self->max_horz = FALSE;
client_maximize(self, TRUE, 1);
- pos = TRUE;
- }
-
- /* if the client didn't get positioned yet, then do so now.
- call client_move even if the window is not being moved anywhere, because
- when we reparent it and decorate it, it is getting moved and we need to
- be telling it so with a ConfigureNotify event.
- */
- if (!pos) {
- /* use the saved position */
- self->area.x = ox;
- self->area.y = oy;
- client_move(self, x, y);
}
/* nothing to do for the other states:
(resized && config_resize_redraw))));
/* 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));
+ if (send_resize_client && (w > oldw || h > oldh)) {
+ XResizeWindow(ob_display, self->window,
+ MAX(w, oldw), MAX(h, oldh));
/* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
}
}
/* if the client is shrinking, then resize the frame before the client */
- if (send_resize_client && (!user || (w <= oldw || h <= oldh))) {
+ if (send_resize_client && (w <= oldw || h <= oldh)) {
/* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
- XResizeWindow(ob_display, self->window, w, h);
+ if (send_resize_client)
+ XResizeWindow(ob_display, self->window, w, h);
}
XFlush(ob_display);
"Focusing client \"%s\" at time %u\n",
self->title, event_curtime);
+ /* if there is a grab going on, then we need to cancel it. if we move
+ focus during the grab, applications will get NotifyWhileGrabbed events
+ and ignore them !
+
+ actions should not rely on being able to move focus during an
+ interactive grab.
+ */
+ if (keyboard_interactively_grabbed())
+ keyboard_interactive_cancel();
+
if (self->can_focus) {
/* This can cause a BadMatch error with CurrentTime, or if an app
passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
OB_CLIENT_FUNC_MAXIMIZE = 1 << 3, /*!< Allow to be maximized */
OB_CLIENT_FUNC_SHADE = 1 << 4, /*!< Allow to be shaded */
OB_CLIENT_FUNC_FULLSCREEN = 1 << 5, /*!< Allow to be made fullscreen */
- OB_CLIENT_FUNC_CLOSE = 1 << 6 /*!< Allow to be closed */
+ OB_CLIENT_FUNC_CLOSE = 1 << 6, /*!< Allow to be closed */
+ OB_CLIENT_FUNC_ABOVE = 1 << 7, /*!< Allow to be put in lower layer */
+ OB_CLIENT_FUNC_BELOW = 1 << 8 /*!< Allow to be put in higher layer */
} ObFunctions;
struct _ObClient
/* Callback functions */
/*! Get notified when the client is unmanaged */
-void client_add_destructor(ObClientCallback func, gpointer data);
-void client_remove_destructor(ObClientCallback func);
+void client_add_destroy_notify(ObClientCallback func, gpointer data);
+void client_remove_destroy_notify(ObClientCallback func);
+
+/*! Get notified when the client is hidden */
+void client_add_hide_notify(ObClientCallback func, gpointer data);
+void client_remove_hide_notify(ObClientCallback func);
/*! Manages all existing windows */
void client_manage_all();
void client_list_combined_menu_startup(gboolean reconfig)
{
if (!reconfig)
- client_add_destructor(client_dest, NULL);
+ client_add_destroy_notify(client_dest, NULL);
combined_menu = menu_new(MENU_NAME, _("Windows"), TRUE, NULL);
menu_set_update_func(combined_menu, self_update);
void client_list_combined_menu_shutdown(gboolean reconfig)
{
if (!reconfig)
- client_remove_destructor(client_dest);
+ client_remove_destroy_notify(client_dest);
}
ObMenu *menu;
if (!reconfig)
- client_add_destructor(client_dest, NULL);
+ client_add_destroy_notify(client_dest, NULL);
menu = menu_new(MENU_NAME, _("Desktops"), TRUE, NULL);
menu_set_update_func(menu, self_update);
void client_list_menu_shutdown(gboolean reconfig)
{
if (!reconfig)
- client_remove_destructor(client_dest);
+ client_remove_destroy_notify(client_dest);
}
if (e->type == OB_MENU_ENTRY_TYPE_NORMAL) {
switch (e->id) {
case LAYER_TOP:
- *en = !c->above;
+ *en = !c->above && (c->functions & OB_CLIENT_FUNC_ABOVE);
break;
case LAYER_NORMAL:
*en = c->above || c->below;
break;
case LAYER_BOTTOM:
- *en = !c->below;
+ *en = !c->below && (c->functions & OB_CLIENT_FUNC_BELOW);
break;
default:
*en = TRUE;
IceAddConnectionWatch(ice_watch, NULL);
#endif
- client_add_destructor(focus_delay_client_dest, NULL);
+ client_add_destroy_notify(focus_delay_client_dest, NULL);
}
void event_shutdown(gboolean reconfig)
IceRemoveConnectionWatch(ice_watch, NULL);
#endif
- client_remove_destructor(focus_delay_client_dest);
+ client_remove_destroy_notify(focus_delay_client_dest);
}
static Window event_get_window(XEvent *e)
Bool event_look_for_focusin_client(Display *d, XEvent *e, XPointer arg)
{
+ ObWindow *w;
+
+ /* It is possible to get FocusIn events or unmanaged windows, meaning
+ they won't be for any known client */
return e->type == FocusIn && wanted_focusevent(e, TRUE) &&
- e->xfocus.window != screen_support_win;
+ (w = g_hash_table_lookup(window_map, &e->xfocus.window)) &&
+ WINDOW_IS_CLIENT(w);
}
static void print_focusevent(XEvent *e)
if (!focus_left_screen)
focus_fallback(TRUE);
}
- } else if (client && client != focus_client) {
+ }
+ else if (!client) {
+ /* It is possible to get FocusIn events or unmanaged windows,
+ meaning they won't be for any known client
+
+ If this happens, set the client to NULL so we know focus
+ has wandered off, and we'll get a focus out for it
+ shortly.
+ */
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to an invalid target\n");
+ focus_set_client(NULL);
+ }
+ else if (client != focus_client) {
focus_left_screen = FALSE;
frame_adjust_focus(client->frame, TRUE);
focus_set_client(client);
gboolean all_desktops,
gboolean dock_windows,
gboolean desktop_windows);
-static void focus_cycle_destructor(ObClient *client, gpointer data);
-static void focus_tried_destructor(ObClient *client, gpointer data);
+static void focus_cycle_destroy_notify(ObClient *client, gpointer data);
+static void focus_tried_hide_notify(ObClient *client, gpointer data);
static Window createWindow(Window parent, gulong mask,
XSetWindowAttributes *attrib)
if (!reconfig) {
XSetWindowAttributes attr;
- client_add_destructor(focus_cycle_destructor, NULL);
- client_add_destructor(focus_tried_destructor, NULL);
+ client_add_destroy_notify(focus_cycle_destroy_notify, NULL);
+ client_add_destroy_notify(focus_tried_hide_notify, NULL);
+ client_add_hide_notify(focus_tried_hide_notify, NULL);
/* start with nothing focused */
focus_nothing();
icon_popup_free(focus_cycle_popup);
if (!reconfig) {
- client_remove_destructor(focus_cycle_destructor);
- client_remove_destructor(focus_tried_destructor);
+ client_remove_destroy_notify(focus_cycle_destroy_notify);
+ client_remove_destroy_notify(focus_tried_hide_notify);
+ client_remove_hide_notify(focus_tried_hide_notify);
/* reset focus to root */
XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
g_free(showtext);
}
-static void focus_cycle_destructor(ObClient *client, gpointer data)
+static void focus_cycle_destroy_notify(ObClient *client, gpointer data)
{
/* end cycling if the target disappears. CurrentTime is fine, time won't
be used
/* the currently selected window isn't interesting */
if(cur == c)
continue;
- if (!dock_windows && !desktop_windows && !client_normal(cur))
+ if (cur->type == OB_CLIENT_TYPE_DOCK && !dock_windows)
continue;
- if (!(dock_windows && cur->type == OB_CLIENT_TYPE_DOCK) ||
- (desktop_windows && cur->type == OB_CLIENT_TYPE_DESKTOP))
+ if (cur->type == OB_CLIENT_TYPE_DESKTOP && !desktop_windows)
+ continue;
+ if (!client_normal(cur) &&
+ cur->type != OB_CLIENT_TYPE_DOCK &&
+ cur->type != OB_CLIENT_TYPE_DESKTOP)
continue;
/* using c->desktop instead of screen_desktop doesn't work if the
* current window was omnipresent, hope this doesn't have any other
return NULL;
}
-static void focus_tried_destructor(ObClient *client, gpointer data)
+static void focus_tried_hide_notify(ObClient *client, gpointer data)
{
XEvent ce;
if (ungrab)
grab_keyboard(FALSE);
+ /* set this before running the actions so they know the keyboard is not
+ grabbed */
+ istate.active = FALSE;
+
alist = g_slist_append(NULL, istate.action);
action_run_interactive(alist, istate.client, state, time, cancel, TRUE);
g_slist_free(alist);
-
- istate.active = FALSE;
}
static void keyboard_interactive_end_client(ObClient *client, gpointer data)
istate.client = NULL;
}
+
+void keyboard_interactive_cancel()
+{
+ keyboard_interactive_end(0, TRUE, event_curtime, TRUE);
+}
+
gboolean keyboard_interactive_grab(guint state, ObClient *client,
ObAction *action)
{
popup = popup_new(FALSE);
if (!reconfig)
- client_add_destructor(keyboard_interactive_end_client, NULL);
+ client_add_destroy_notify(keyboard_interactive_end_client, NULL);
}
void keyboard_shutdown(gboolean reconfig)
{
if (!reconfig)
- client_remove_destructor(keyboard_interactive_end_client);
+ client_remove_destroy_notify(keyboard_interactive_end_client);
if (istate.active)
- keyboard_interactive_end(0, TRUE, 0, TRUE);
+ keyboard_interactive_cancel();
ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
struct _ObClient **client);
gboolean keyboard_interactively_grabbed();
+void keyboard_interactive_cancel();
+
#endif
loop->run = TRUE;
loop->running = TRUE;
- client_add_destructor(ob_main_loop_client_destroy, loop);
+ client_add_destroy_notify(ob_main_loop_client_destroy, loop);
while (loop->run) {
if (loop->signal_fired) {
}
}
- client_remove_destructor(ob_main_loop_client_destroy);
+ client_remove_destroy_notify(ob_main_loop_client_destroy);
loop->running = FALSE;
}
g_assert(menu_parse_state.parent == NULL);
if (!reconfig)
- client_add_destructor(client_dest, NULL);
+ client_add_destroy_notify(client_dest, NULL);
}
void menu_shutdown(gboolean reconfig)
{
if (!reconfig)
- client_remove_destructor(client_dest);
+ client_remove_destroy_notify(client_dest);
parse_shutdown(menu_parse_inst);
menu_parse_inst = NULL;
popup = popup_new(FALSE);
if (!reconfig)
- client_add_destructor(client_dest, NULL);
+ client_add_destroy_notify(client_dest, NULL);
}
void moveresize_shutdown(gboolean reconfig)
if (!reconfig) {
if (moveresize_in_progress)
moveresize_end(FALSE);
- client_remove_destructor(client_dest);
+ client_remove_destroy_notify(client_dest);
}
popup_free(popup);
CREATE(net_wm_action_fullscreen, "_NET_WM_ACTION_FULLSCREEN");
CREATE(net_wm_action_change_desktop, "_NET_WM_ACTION_CHANGE_DESKTOP");
CREATE(net_wm_action_close, "_NET_WM_ACTION_CLOSE");
+ CREATE(net_wm_action_above, "_NET_WM_ACTION_ABOVE");
+ CREATE(net_wm_action_below, "_NET_WM_ACTION_BELOW");
+
CREATE(net_wm_state_modal, "_NET_WM_STATE_MODAL");
/* CREATE(net_wm_state_sticky, "_NET_WM_STATE_STICKY");*/
CREATE(net_wm_state_maximized_vert, "_NET_WM_STATE_MAXIMIZED_VERT");
Atom net_wm_action_resize;
Atom net_wm_action_minimize;
Atom net_wm_action_shade;
+/* Atom net_wm_action_stick;*/
Atom net_wm_action_maximize_horz;
Atom net_wm_action_maximize_vert;
Atom net_wm_action_fullscreen;
Atom net_wm_action_change_desktop;
Atom net_wm_action_close;
+ Atom net_wm_action_above;
+ Atom net_wm_action_below;
Atom net_wm_state_modal;
/* Atom net_wm_state_sticky;*/
supported[i++] = prop_atoms.net_wm_action_fullscreen;
supported[i++] = prop_atoms.net_wm_action_change_desktop;
supported[i++] = prop_atoms.net_wm_action_close;
+ supported[i++] = prop_atoms.net_wm_action_above;
+ supported[i++] = prop_atoms.net_wm_action_below;
supported[i++] = prop_atoms.net_wm_state;
supported[i++] = prop_atoms.net_wm_state_modal;
supported[i++] = prop_atoms.net_wm_state_maximized_vert;
desktop_cycle_popup = pager_popup_new(FALSE);
pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
- if (reconfig)
+ if (reconfig) {
+ /* update the pager popup's width */
+ pager_popup_text_width_to_strings(desktop_cycle_popup,
+ screen_desktop_names,
+ screen_num_desktops);
return;
+ }
/* get the initial size */
screen_resize();