+ _NET_WM_STRUT (1.3)
+ _NET_WM_STRUT_PARTIAL (1.3)
Openbox uses these to create per-monitor struts in Xinerama setups.
-- _NET_WM_ICON_GEOMETRY (1.3)
- Openbox does not display icons for iconic windows.
++ _NET_WM_ICON_GEOMETRY (1.3)
+ _NET_WM_ICON (1.3)
- _NET_WM_PID (1.3)
- Openbox does not make use of available PIDs as I don't believe there is
- a reliable way to tell what client the window is running on.
+ Openbox does not currently kill processes.
- _NET_WM_HANDLED_ICONS (1.3)
Openbox does not display icons for iconic windows.
+ _NET_WM_USER_TIME (1.3)
++ _NET_WM_USER_TIME_WINDOW (1.4)
- _NET_WM_PING (1.3)
Openbox doesn't look for hung processes at this time.
+ _NET_FRAME_EXTENTS (1.3)
+ _NET_WM_SYNC_REQUEST (1.3)
+ _NET_WM_FULL_PLACEMENT (1.4)
+ _NET_WM_MOVERESIZE_CANCEL (1.4)
-- _NET_REQUEST_FRAME_EXTENTS (1.3)
++ _NET_REQUEST_FRAME_EXTENTS (1.3)
client_action_end(data);
}
-static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
+static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
+ gboolean shaded)
{
/* let's make x and y client relative instead of screen relative */
x = x - cx;
|CCCCCCC | A B | DDDDDDD|
| CCCCCCCC | A | | B | DDDDDDDD |
| CCCCCCC A B DDDDDDD |
- - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - -
- | | b c | |
- | west | b move c | east |
- | | b c | |
- - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - -
+ - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
+ | | b c | | sh
+ | west | b move c | east | ad
+ | | b c | | ed
+ - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
| EEEEEEE G H FFFFFFF |
| EEEEEEEE | G | | H | FFFFFFFF |
|EEEEEEE | G H | FFFFFFF|
+---------------------G-------|-------|-------H---------------------+
*/
+ if (shaded) {
+ /* for shaded windows, you can only resize west/east and move */
+ if (b)
+ return prop_atoms.net_wm_moveresize_size_left;
+ if (c)
+ return prop_atoms.net_wm_moveresize_size_right;
+ return prop_atoms.net_wm_moveresize_move;
+ }
+
if (y < A && y >= C)
return prop_atoms.net_wm_moveresize_size_topleft;
else if (y >= A && y >= B && a)
c->area.width + c->frame->size.left +
c->frame->size.right,
c->area.height + c->frame->size.top +
- c->frame->size.bottom));
+ c->frame->size.bottom, c->shaded));
}
moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
static GSList *client_destructors = NULL;
-static void client_get_all(ObClient *self);
+static void client_get_all(ObClient *self, gboolean real);
static void client_toggle_border(ObClient *self, gboolean show);
static void client_get_startup_id(ObClient *self);
static void client_get_session_ids(ObClient *self);
static void client_get_layer(ObClient *self);
static void client_get_shaped(ObClient *self);
static void client_get_mwm_hints(ObClient *self);
-static void client_get_gravity(ObClient *self);
static void client_get_colormap(ObClient *self);
-static void client_get_transientness(ObClient *self);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
grab_server(TRUE);
- /* check if it has already been unmapped by the time we started mapping.
- the grab does a sync so we don't have to here */
+ /* check if it has already been unmapped by the time we started
+ mapping. the grab does a sync so we don't have to here */
if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
{
XChangeWindowAttributes(ob_display, window,
CWEventMask|CWDontPropagate, &attrib_set);
-
/* create the ObClient struct, and populate it from the hints on the
window */
self = g_new0(ObClient, 1);
self->desktop = screen_num_desktops; /* always an invalid value */
self->user_time = focus_client ? focus_client->user_time : CurrentTime;
- client_get_all(self);
+ client_get_all(self, TRUE);
/* per-app settings override stuff, and return the settings for other
uses too */
settings = client_get_settings_state(self);
/* remove the client's border (and adjust re gravity) */
client_toggle_border(self, FALSE);
- /* specify that if we exit, the window should not be destroyed and should
- be reparented back to root automatically */
+ /* specify that if we exit, the window should not be destroyed and
+ should be reparented back to root automatically */
XChangeSaveSet(ob_display, window, SetModeInsert);
/* create the decoration frame for the client window */
self->frame = frame_new(self);
- frame_grab_client(self->frame, self);
+ frame_grab_client(self->frame);
/* do this after we have a frame.. it uses the frame to help determine the
WM_STATE to apply. */
client_set_list();
ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
+
+ return;
+}
+
+
+ObClient *client_fake_manage(Window window)
+{
+ ObClient *self;
+ ObAppSettings *settings;
+
+ ob_debug("Pretend-managing window: %lx\n", window);
+
+ /* do this minimal stuff to figure out the client's decorations */
+
+ self = g_new0(ObClient, 1);
+ self->window = window;
+
+ client_get_all(self, FALSE);
+ /* per-app settings override stuff, and return the settings for other
+ uses too */
+ settings = client_get_settings_state(self);
+
+ /* create the decoration frame for the client window */
+ self->frame = frame_new(self);
+ return self;
}
void client_unmanage_all()
guint j;
GSList *it;
- ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class,
- self->title ? self->title : "");
+ ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window,
+ self->class, self->title ? self->title : "");
g_assert(self != NULL);
/* flush to send the hide to the server quickly */
XFlush(ob_display);
- /* ignore enter events from the unmap so it doesnt mess with the focus */
+ /* ignore enter events from the unmap so it doesnt mess with the
+ focus */
event_ignore_queued_enters();
mouse_grab_for_client(self, FALSE);
for (it = self->group->members; it; it = g_slist_next(it))
if (it->data != self)
((ObClient*)it->data)->transients =
- g_slist_remove(((ObClient*)it->data)->transients, self);
+ g_slist_remove(((ObClient*)it->data)->transients,self);
} else if (self->transient_for) { /* transient of window */
self->transient_for->transients =
g_slist_remove(self->transient_for->transients, self);
}
/* reparent the window out of the frame, and free the frame */
- frame_release_client(self->frame, self);
+ frame_release_client(self->frame);
+ frame_free(self->frame);
self->frame = NULL;
if (ob_state() != OB_STATE_EXITING) {
PROP_ERASE(self->window, net_wm_state);
PROP_ERASE(self->window, wm_state);
} else {
- /* if we're left in an unmapped state, the client wont be mapped. this
- is bad, since we will no longer be managing the window on restart */
+ /* if we're left in an unmapped state, the client wont be mapped.
+ this is bad, since we will no longer be managing the window on
+ restart */
XMapWindow(ob_display, self->window);
}
+ /* update the list hints */
+ client_set_list();
+
ob_debug("Unmanaged window 0x%lx\n", self->window);
/* free all data allocated in the client struct */
g_free(self->client_machine);
g_free(self->sm_client_id);
g_free(self);
-
- /* update the list hints */
- client_set_list();
+}
+
+void client_fake_unmanage(ObClient *self)
+{
+ /* this is all that got allocated to get the decorations */
+
+ frame_free(self->frame);
+ g_free(self);
}
static ObAppSettings *client_get_settings_state(ObClient *self)
}
-static void client_get_all(ObClient *self)
+static void client_get_all(ObClient *self, gboolean real)
{
+ /* this is needed for the frame to set itself up */
client_get_area(self);
- client_get_mwm_hints(self);
-
- /* The transient-ness of a window is used to pick a type, but the type can
- also affect transiency.
- Dialogs are always made transients for their group if they have one.
+ /* these things can change the decor and functions of the window */
- I also have made non-application type windows be transients for their
- group (eg utility windows).
- */
- client_get_transientness(self);
- client_get_type(self);/* this can change the mwmhints for special cases */
+ client_get_mwm_hints(self);
+ /* this can change the mwmhints for special cases */
+ client_get_type_and_transientness(self);
client_get_state(self);
+ client_update_protocols(self);
+ client_update_normal_hints(self);
- client_update_wmhints(self);
- /* this may have already been called from client_update_wmhints */
- if (self->transient_for == NULL)
- client_update_transient_for(self);
- client_get_startup_id(self);
- client_get_desktop(self);/* uses transient data/group/startup id if a
- desktop is not specified */
- client_get_shaped(self);
-
- client_get_layer(self); /* if layer hasn't been specified, get it from
- other sources if possible */
+ /* got the type, the mwmhints, the protocols, and the normal hints
+ (min/max sizes), so we're ready to set up the decorations/functions */
+ client_setup_decor_and_functions(self);
- {
- /* a couple type-based defaults for new windows */
+ if (real) {
+ client_update_wmhints(self);
+ /* this may have already been called from client_update_wmhints */
+ if (self->transient_for == NULL)
+ client_update_transient_for(self);
- /* this makes sure that these windows appear on all desktops */
- if (self->type == OB_CLIENT_TYPE_DESKTOP)
- self->desktop = DESKTOP_ALL;
- }
+ client_get_startup_id(self);
+ client_get_desktop(self);/* uses transient data/group/startup id if a
+ desktop is not specified */
+ client_get_shaped(self);
- client_update_protocols(self);
+ client_get_layer(self); /* if layer hasn't been specified, get it from
+ other sources if possible */
- client_get_gravity(self); /* get the attribute gravity */
- client_update_normal_hints(self); /* this may override the attribute
- gravity */
+ {
+ /* a couple type-based defaults for new windows */
- /* got the type, the mwmhints, the protocols, and the normal hints
- (min/max sizes), so we're ready to set up the decorations/functions */
- client_setup_decor_and_functions(self);
+ /* this makes sure that these windows appear on all desktops */
+ if (self->type == OB_CLIENT_TYPE_DESKTOP)
+ self->desktop = DESKTOP_ALL;
+ }
#ifdef SYNC
- client_update_sync_request_counter(self);
+ client_update_sync_request_counter(self);
#endif
- /* get the session related properties */
- client_get_session_ids(self);
+ /* get the session related properties */
+ client_get_session_ids(self);
- client_get_colormap(self);
- client_update_title(self);
- client_update_strut(self);
- client_update_icons(self);
- client_update_user_time_window(self);
- if (!self->user_time_window) /* check if this would have been called */
- client_update_user_time(self);
- client_update_icon_geometry(self);
+ client_get_colormap(self);
+ client_update_title(self);
+ client_update_strut(self);
+ client_update_icons(self);
+ client_update_user_time_window(self);
+ if (!self->user_time_window) /* check if this would have been called */
+ client_update_user_time(self);
+ client_update_icon_geometry(self);
+ }
}
static void client_get_startup_id(ObClient *self)
#endif
}
-void client_get_transientness(ObClient *self)
-{
- Window t;
- if (XGetTransientForHint(ob_display, self->window, &t))
- self->transient = TRUE;
-}
-
void client_update_transient_for(ObClient *self)
{
Window t = None;
ObClient *target = NULL;
if (XGetTransientForHint(ob_display, self->window, &t)) {
- self->transient = TRUE;
if (t != self->window) { /* cant be transient to itself! */
target = g_hash_table_lookup(window_map, &t);
/* if this happens then we need to check for it*/
}
}
}
- } else if (self->type == OB_CLIENT_TYPE_DIALOG ||
- self->type == OB_CLIENT_TYPE_TOOLBAR ||
- self->type == OB_CLIENT_TYPE_MENU ||
- self->type == OB_CLIENT_TYPE_UTILITY)
- {
- self->transient = TRUE;
- if (self->group)
- target = OB_TRAN_GROUP;
- } else
- self->transient = FALSE;
+ } else if (self->transient && self->group)
+ target = OB_TRAN_GROUP;
client_update_transient_tree(self, self->group, self->group,
self->transient_for, target);
}
}
-void client_get_type(ObClient *self)
+void client_get_type_and_transientness(ObClient *self)
{
guint num, i;
guint32 *val;
+ Window t;
self->type = -1;
+ self->transient = FALSE;
if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
/* use the first value that we know about in the array */
}
g_free(val);
}
-
+
+ if (XGetTransientForHint(ob_display, self->window, &t))
+ self->transient = TRUE;
+
if (self->type == (ObClientType) -1) {
/*the window type hint was not set, which means we either classify
ourself as a normal window or a dialog, depending on if we are a
else
self->type = OB_CLIENT_TYPE_NORMAL;
}
+
+ /* then, based on our type, we can update our transientness.. */
+ if (self->type == OB_CLIENT_TYPE_DIALOG ||
+ self->type == OB_CLIENT_TYPE_TOOLBAR ||
+ self->type == OB_CLIENT_TYPE_MENU ||
+ self->type == OB_CLIENT_TYPE_UTILITY)
+ {
+ self->transient = TRUE;
+ }
}
void client_update_protocols(ObClient *self)
}
#endif
-static void client_get_gravity(ObClient *self)
-{
- XWindowAttributes wattrib;
- Status ret;
-
- ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
- g_assert(ret != BadWindow);
- self->gravity = wattrib.win_gravity;
-}
-
void client_get_colormap(ObClient *self)
{
XWindowAttributes wa;
/* kill the handle on fully maxed windows */
if (self->max_vert && self->max_horz)
- self->decorations &= ~OB_FRAME_DECOR_HANDLE;
+ self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS);
/* finally, the user can have requested no decorations, which overrides
everything (but doesnt give it a border if it doesnt have one) */
localhost[127] = '\0';
if (strcmp(localhost, s) != 0)
self->client_machine = s;
+ else
+ g_free(s);
}
}
/*! Manages all existing windows */
void client_manage_all();
-/*! Manages a given window */
+/*! Manages a given window
+*/
void client_manage(Window win);
/*! Unmanages all managed windows */
void client_unmanage_all();
/*! Unmanages a given client */
void client_unmanage(ObClient *client);
+/*! This manages a window only so far as is needed to get it's decorations.
+ This is used when you want to determine a window's decorations before it
+ is mapped. Call client_fake_unmanage() with the returned client when you
+ are done with it. */
+ObClient *client_fake_manage(Window win);
+/*! Free the stuff created by client_fake_manage() */
+void client_fake_unmanage(ObClient *self);
+
/*! Sets the client list on the root window from the client_list */
void client_set_list();
/*! Convery a position/size from a given gravity to the client's true gravity
*/
-void client_convert_gravity(ObClient *client, gint gravity, gint *x, gint *y,
+void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
gint w, gint h);
#define client_move(self, x, y) \
/*! Bring all of its helper windows to its desktop. These are the utility and
stuff windows. */
-void client_bring_helper_windows(ObClient *client);
+void client_bring_helper_windows(ObClient *self);
/*! Calculates the stacking layer for the client window */
void client_calc_layer(ObClient *self);
*/
void client_setup_decor_and_functions(ObClient *self);
-/*! Retrieves the window's type and sets ObClient->type */
-void client_get_type(ObClient *self);
+/*! Sets the window's type and transient flag */
+void client_get_type_and_transientness(ObClient *self);
const ObClientIcon *client_icon(ObClient *self, gint w, gint h);
event_handle_root(e);
else if (e->type == MapRequest)
client_manage(window);
+ else if (e->type == ClientMessage) {
+ /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
+ windows that are not managed yet. */
+ if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
+ /* Pretend to manage the client, getting information used to
+ determine its decorations */
+ ObClient *c = client_fake_manage(e->xclient.window);
+ gulong vals[4];
+
+ /* adjust the decorations so we know the sizes */
+ frame_adjust_area(c->frame, FALSE, TRUE, TRUE);
+
+ /* set the frame extents on the window */
+ vals[0] = c->frame->size.left;
+ vals[1] = c->frame->size.right;
+ vals[2] = c->frame->size.top;
+ vals[3] = c->frame->size.bottom;
+ PROP_SETA32(e->xclient.window, net_frame_extents,
+ cardinal, vals, 4);
+
+ /* Free the pretend client */
+ client_fake_unmanage(c);
+ }
+ }
else if (e->type == ConfigureRequest) {
- /* unhandled configure requests must be used to configure the
+ /* unhandled config5Aure requests must be used to configure the
window directly */
XWindowChanges xwc;
XEvent ce;
Atom msgtype;
ObFrameContext con;
+ static gint px = -1, py = -1;
+ static guint pb = 0;
switch (e->type) {
case ButtonPress:
+ /* save where the press occured for the first button pressed */
+ if (!pb) {
+ pb = e->xbutton.button;
+ px = e->xbutton.x;
+ py = e->xbutton.y;
+ }
case ButtonRelease:
/* Wheel buttons don't draw because they are an instant click, so it
is a waste of resources to go drawing it.
!keyboard_interactively_grabbed() &&
!menu_frame_visible)
{
- con = frame_context(client, e->xbutton.window);
+ /* use where the press occured */
+ con = frame_context(client, e->xbutton.window, px, py);
con = mouse_button_frame_context(con, e->xbutton.button);
+
+ if (e->type == ButtonRelease && e->xbutton.button == pb)
+ pb = 0, px = py = -1;
+
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_press = (e->type == ButtonPress);
}
}
break;
+ case MotionNotify:
+ con = frame_context(client, e->xmotion.window,
+ e->xmotion.x, e->xmotion.y);
+ switch (con) {
+ case OB_FRAME_CONTEXT_TITLEBAR:
+ /* we've left the button area inside the titlebar */
+ client->frame->max_hover = FALSE;
+ client->frame->desk_hover = FALSE;
+ client->frame->shade_hover = FALSE;
+ client->frame->iconify_hover = FALSE;
+ client->frame->close_hover = FALSE;
+ frame_adjust_state(client->frame);
+ break;
+ case OB_FRAME_CONTEXT_MAXIMIZE:
+ client->frame->max_hover = TRUE;
+ frame_adjust_state(client->frame);
+ break;
+ case OB_FRAME_CONTEXT_ALLDESKTOPS:
+ client->frame->desk_hover = TRUE;
+ frame_adjust_state(client->frame);
+ break;
+ case OB_FRAME_CONTEXT_SHADE:
+ client->frame->shade_hover = TRUE;
+ frame_adjust_state(client->frame);
+ break;
+ case OB_FRAME_CONTEXT_ICONIFY:
+ client->frame->iconify_hover = TRUE;
+ frame_adjust_state(client->frame);
+ break;
+ case OB_FRAME_CONTEXT_CLOSE:
+ client->frame->close_hover = TRUE;
+ frame_adjust_state(client->frame);
+ break;
+ default:
+ break;
+ }
+ break;
case LeaveNotify:
- con = frame_context(client, e->xcrossing.window);
+ con = frame_context(client, e->xcrossing.window,
+ e->xcrossing.x, e->xcrossing.y);
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_hover = FALSE;
nofocus = TRUE;
}
- con = frame_context(client, e->xcrossing.window);
+ con = frame_context(client, e->xcrossing.window,
+ e->xcrossing.x, e->xcrossing.y);
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_hover = TRUE;
client_update_wmhints(client);
} else if (msgtype == XA_WM_TRANSIENT_FOR) {
client_update_transient_for(client);
- client_get_type(client);
+ client_get_type_and_transientness(client);
/* type may have changed, so update the layer */
client_calc_layer(client);
client_setup_decor_and_functions(client);
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
ButtonPressMask | ButtonReleaseMask)
#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
- ButtonMotionMask | \
+ ButtonMotionMask | PointerMotionMask | \
EnterWindowMask | LeaveWindowMask)
/* The inner window does not need enter/leave events.
If it does get them, then it needs its own context for enter events
Visual *visual;
self = g_new0(ObFrame, 1);
+ self->client = client;
visual = check_32bit_client(client);
RrAppearanceFree(self->a_icon);
}
-static void frame_free(ObFrame *self)
+void frame_free(ObFrame *self)
{
free_theme_statics(self);
framerender_frame(self);
}
-void frame_grab_client(ObFrame *self, ObClient *client)
+void frame_grab_client(ObFrame *self)
{
- self->client = client;
-
/* reparent the client to the frame */
- XReparentWindow(ob_display, client->window, self->plate, 0, 0);
+ XReparentWindow(ob_display, self->client->window, self->plate, 0, 0);
/*
When reparenting the client window, it is usually not mapped yet, since
this occurs from a MapRequest. However, in the case where Openbox is
handled and need to be ignored.
*/
if (ob_state() == OB_STATE_STARTING)
- client->ignore_unmaps += 2;
+ self->client->ignore_unmaps += 2;
/* select the event mask on the client's parent (to receive config/map
req's) the ButtonPress is to catch clicks on the client border */
XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
/* map the client so it maps when the frame does */
- XMapWindow(ob_display, client->window);
+ XMapWindow(ob_display, self->client->window);
/* adjust the frame to the client's size */
frame_adjust_area(self, FALSE, TRUE, FALSE);
/* set all the windows for the frame in the window_map */
- g_hash_table_insert(window_map, &self->window, client);
- g_hash_table_insert(window_map, &self->plate, client);
- g_hash_table_insert(window_map, &self->inner, client);
- g_hash_table_insert(window_map, &self->title, client);
- g_hash_table_insert(window_map, &self->label, client);
- g_hash_table_insert(window_map, &self->max, client);
- g_hash_table_insert(window_map, &self->close, client);
- g_hash_table_insert(window_map, &self->desk, client);
- g_hash_table_insert(window_map, &self->shade, client);
- g_hash_table_insert(window_map, &self->icon, client);
- g_hash_table_insert(window_map, &self->iconify, client);
- g_hash_table_insert(window_map, &self->handle, client);
- g_hash_table_insert(window_map, &self->lgrip, client);
- g_hash_table_insert(window_map, &self->rgrip, client);
- g_hash_table_insert(window_map, &self->tltresize, client);
- g_hash_table_insert(window_map, &self->tllresize, client);
- g_hash_table_insert(window_map, &self->trtresize, client);
- g_hash_table_insert(window_map, &self->trrresize, client);
+ g_hash_table_insert(window_map, &self->window, self->client);
+ g_hash_table_insert(window_map, &self->plate, self->client);
+ g_hash_table_insert(window_map, &self->inner, self->client);
+ g_hash_table_insert(window_map, &self->title, self->client);
+ g_hash_table_insert(window_map, &self->label, self->client);
+ g_hash_table_insert(window_map, &self->max, self->client);
+ g_hash_table_insert(window_map, &self->close, self->client);
+ g_hash_table_insert(window_map, &self->desk, self->client);
+ g_hash_table_insert(window_map, &self->shade, self->client);
+ g_hash_table_insert(window_map, &self->icon, self->client);
+ g_hash_table_insert(window_map, &self->iconify, self->client);
+ g_hash_table_insert(window_map, &self->handle, self->client);
+ g_hash_table_insert(window_map, &self->lgrip, self->client);
+ g_hash_table_insert(window_map, &self->rgrip, self->client);
+ g_hash_table_insert(window_map, &self->tltresize, self->client);
+ g_hash_table_insert(window_map, &self->tllresize, self->client);
+ g_hash_table_insert(window_map, &self->trtresize, self->client);
+ g_hash_table_insert(window_map, &self->trrresize, self->client);
}
-void frame_release_client(ObFrame *self, ObClient *client)
+void frame_release_client(ObFrame *self)
{
XEvent ev;
gboolean reparent = TRUE;
- g_assert(self->client == client);
-
/* if there was any animation going on, kill it */
ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
self, FALSE);
/* check if the app has already reparented its window away */
- while (XCheckTypedWindowEvent(ob_display, client->window,
+ while (XCheckTypedWindowEvent(ob_display, self->client->window,
ReparentNotify, &ev))
{
/* This check makes sure we don't catch our own reparent action to
if (reparent) {
/* according to the ICCCM - if the client doesn't reparent itself,
then we will reparent the window to root for them */
- XReparentWindow(ob_display, client->window,
+ XReparentWindow(ob_display, self->client->window,
RootWindow(ob_display, ob_screen),
- client->area.x,
- client->area.y);
+ self->client->area.x,
+ self->client->area.y);
}
/* remove all the windows for the frame from the window_map */
g_hash_table_remove(window_map, &self->trrresize);
ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
-
- frame_free(self);
}
/* is there anything present between us and the label? */
static void layout_title(ObFrame *self)
{
gchar *lc;
- gint i, x;
+ gint i;
const gint bwidth = ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
/* position of the left most button */
self->icon_on = self->desk_on = self->shade_on = self->iconify_on =
self->max_on = self->close_on = self->label_on = FALSE;
self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
+ self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
/* figure out what's being show, find each element's position, and the
width of the label
i will be +1 the first time through when working to the left,
and -1 the second time through when working to the right */
for (i = 1; i >= -1; i-=2) {
+ gint x;
+ ObFrameContext *firstcon;
+
if (i > 0) {
x = left;
lc = config_title_layout;
+ firstcon = &self->leftmost;
} else {
x = right;
lc = config_title_layout + strlen(config_title_layout)-1;
+ firstcon = &self->rightmost;
}
/* stop at the end of the string (or the label, which calls break) */
- for (; *lc != '\0' && lc >= config_title_layout; lc+=i)
+ for (; *lc != '\0' && lc >= config_title_layout; lc+=i) {
if (*lc == 'L') {
if (i > 0) {
self->label_on = TRUE;
}
break; /* break the for loop, do other side of label */
} else if (*lc == 'N') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICON;
if ((self->icon_on = is_button_present(self, lc, i))) {
/* icon gets extra padding */
self->label_width -= bwidth + 2;
x += i * (bwidth + 2);
}
} else if (*lc == 'D') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
if ((self->desk_on = is_button_present(self, lc, i))) {
self->label_width -= bwidth;
self->desk_x = x;
x += i * bwidth;
}
} else if (*lc == 'S') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_SHADE;
if ((self->shade_on = is_button_present(self, lc, i))) {
self->label_width -= bwidth;
self->shade_x = x;
x += i * bwidth;
}
} else if (*lc == 'I') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICONIFY;
if ((self->iconify_on = is_button_present(self, lc, i))) {
self->label_width -= bwidth;
self->iconify_x = x;
x += i * bwidth;
}
} else if (*lc == 'M') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
if ((self->max_on = is_button_present(self, lc, i))) {
self->label_width -= bwidth;
self->max_x = x;
x += i * bwidth;
}
} else if (*lc == 'C') {
+ if (firstcon) *firstcon = OB_FRAME_CONTEXT_CLOSE;
if ((self->close_on = is_button_present(self, lc, i))) {
self->label_width -= bwidth;
self->close_x = x;
x += i * bwidth;
}
- }
+ } else
+ continue; /* don't set firstcon */
+ firstcon = NULL;
+ }
}
/* position and map the elements */
return OB_FRAME_CONTEXT_NONE;
}
-ObFrameContext frame_context(ObClient *client, Window win)
+ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y)
{
ObFrame *self;
return OB_FRAME_CONTEXT_CLIENT;
}
+ if (win == self->title) {
+ /* when the user clicks in the corners of the titlebar and the client
+ is fully maximized, then treat it like they clicked in the
+ button that is there */
+ if (self->client->max_horz && self->client->max_vert &&
+ y < ob_rr_theme->paddingy + 1 + ob_rr_theme->button_size)
+ {
+ if (x < ((ob_rr_theme->paddingx + 1) * 2 +
+ ob_rr_theme->button_size)) {
+ if (self->leftmost != OB_FRAME_CONTEXT_NONE)
+ return self->leftmost;
+ }
+ else if (x > (self->width -
+ (ob_rr_theme->paddingx + 1 +
+ ob_rr_theme->button_size)))
+ {
+ if (self->rightmost != OB_FRAME_CONTEXT_NONE)
+ return self->rightmost;
+ }
+ }
+ return OB_FRAME_CONTEXT_TITLEBAR;
+ }
+
if (win == self->window) return OB_FRAME_CONTEXT_FRAME;
- if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR;
if (win == self->handle) return OB_FRAME_CONTEXT_HANDLE;
if (win == self->lgrip) return OB_FRAME_CONTEXT_BLCORNER;
gint cbwidth_x; /* client border width */
gint cbwidth_y; /* client border width */
+ /* the leftmost and rightmost elements in the titlebar */
+ ObFrameContext leftmost;
+ ObFrameContext rightmost;
+
gboolean max_press;
gboolean close_press;
gboolean desk_press;
};
ObFrame *frame_new(struct _ObClient *c);
+void frame_free(ObFrame *self);
+
void frame_show(ObFrame *self);
void frame_hide(ObFrame *self);
void frame_adjust_theme(ObFrame *self);
void frame_adjust_focus(ObFrame *self, gboolean hilite);
void frame_adjust_title(ObFrame *self);
void frame_adjust_icon(ObFrame *self);
-void frame_grab_client(ObFrame *self, struct _ObClient *client);
-void frame_release_client(ObFrame *self, struct _ObClient *client);
+void frame_grab_client(ObFrame *self);
+void frame_release_client(ObFrame *self);
ObFrameContext frame_context_from_string(const gchar *name);
-ObFrameContext frame_context(struct _ObClient *self, Window win);
+ObFrameContext frame_context(struct _ObClient *self, Window win,
+ gint x, gint y);
/*! Applies gravity to the client's position to find where the frame should
be positioned.
g_free(self->name);
g_free(self->title);
g_free(self->execute);
+ g_free(self->more_menu);
g_free(self);
}
static void set_modkey_mask(guchar mask, KeySym sym);
static XModifierKeymap *modmap;
+static KeySym *keymap;
+static gint min_keycode, max_keycode, keysyms_per_keycode;
/* This is a bitmask of the different masks for each modifier key */
static guchar modkeys_keys[OB_MODKEY_NUM_KEYS];
void modkeys_startup(gboolean reconfigure)
{
- KeySym *keymap;
gint i, j, k;
- gint min_keycode, max_keycode, keysyms_per_keycode;
/* reset the keys to not be bound to any masks */
for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i)
KeySym sym;
/* get a keycode that is bound to the mask (i) */
KeyCode keycode = modmap->modifiermap[i*modmap->max_keypermod + j];
- /* go through each keysym bound to the given keycode */
- for (k = 0; k < keysyms_per_keycode; ++k) {
- sym = keymap[(keycode-min_keycode) * keysyms_per_keycode + k];
- if (sym != NoSymbol) {
- /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */
- set_modkey_mask(nth_mask(i), sym);
+ if (keycode) {
+ /* go through each keysym bound to the given keycode */
+ for (k = 0; k < keysyms_per_keycode; ++k) {
+ sym = keymap[(keycode-min_keycode) * keysyms_per_keycode +
+ k];
+ if (sym != NoSymbol) {
+ /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */
+ set_modkey_mask(nth_mask(i), sym);
+ }
}
}
}
}
- XFree(keymap);
}
void modkeys_shutdown(gboolean reconfigure)
{
XFreeModifiermap(modmap);
+ XFree(keymap);
}
guint modkeys_keycode_to_mask(guint keycode)
else if (sym == XK_Meta_L || sym == XK_Meta_R)
modkeys_keys[OB_MODKEY_KEY_META] |= mask;
}
+
+KeyCode modkeys_sym_to_code(KeySym sym)
+{
+ gint i, j;
+
+ /* go through each keycode and look for the keysym */
+ for (i = min_keycode; i <= max_keycode; ++i)
+ for (j = 0; j < keysyms_per_keycode; ++j)
+ if (sym == keymap[(i-min_keycode) * keysyms_per_keycode + j])
+ return i;
+ return 0;
+}
+
#define ob__modkeys_h
#include <glib.h>
+#include <X11/Xlib.h>
/*! These keys are bound to the modifier masks in any fashion */
typedef enum {
right keys when there are both. */
guint modkeys_key_to_mask(ObModkeysKey key);
+/*! Convert a KeySym to a KeyCode, because the X function is terrible - says
+ valgrind. */
+KeyCode modkeys_sym_to_code(KeySym sym);
+
#endif
static Time ltime;
static guint button = 0, state = 0, lbutton = 0;
static Window lwindow = None;
- static gint px, py;
+ static gint px, py, pwx = -1, pwy = -1;
ObFrameContext context;
gboolean click = FALSE;
switch (e->type) {
case ButtonPress:
- context = frame_context(client, e->xany.window);
+ context = frame_context(client, e->xbutton.window,
+ e->xbutton.x, e->xbutton.y);
context = mouse_button_frame_context(context, e->xbutton.button);
px = e->xbutton.x_root;
py = e->xbutton.y_root;
+ if (pwx == -1) pwx = e->xbutton.x;
+ if (pwy == -1) pwy = e->xbutton.y;
button = e->xbutton.button;
state = e->xbutton.state;
break;
case ButtonRelease:
- context = frame_context(client, e->xany.window);
+ /* use where the press occured in the window */
+ context = frame_context(client, e->xbutton.window, pwx, pwy);
context = mouse_button_frame_context(context, e->xbutton.button);
+ pwx = pwy = -1;
+
if (e->xbutton.button == button) {
/* clicks are only valid if its released over the window */
gint junk1, junk2;
case MotionNotify:
if (button) {
- context = frame_context(client, e->xany.window);
+ context = frame_context(client, e->xmotion.window, pwx, pwy);
context = mouse_button_frame_context(context, button);
if (ABS(e->xmotion.x_root - px) >=
#include <X11/Xcursor/Xcursor.h>
#endif
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+
RrInstance *ob_rr_inst;
RrTheme *ob_rr_theme;
ObMainLoop *ob_main_loop;
cursors[OB_CURSOR_NORTHWEST] = load_cursor("top_left_corner",
XC_top_left_corner);
- /* create available keycodes */
- keys[OB_KEY_RETURN] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Return"));
- keys[OB_KEY_ESCAPE] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Escape"));
- keys[OB_KEY_LEFT] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Left"));
- keys[OB_KEY_RIGHT] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Right"));
- keys[OB_KEY_UP] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Up"));
- keys[OB_KEY_DOWN] =
- XKeysymToKeycode(ob_display, XStringToKeysym("Down"));
prop_startup(); /* get atoms values for the display */
extensions_query_all(); /* find which extensions are present */
if (screen_annex(program_name)) { /* it will be ours! */
do {
+ modkeys_startup(reconfigure);
+
+ /* get the keycodes for keys we use */
+ keys[OB_KEY_RETURN] = modkeys_sym_to_code(XK_Return);
+ keys[OB_KEY_ESCAPE] = modkeys_sym_to_code(XK_Escape);
+ keys[OB_KEY_LEFT] = modkeys_sym_to_code(XK_Left);
+ keys[OB_KEY_RIGHT] = modkeys_sym_to_code(XK_Right);
+ keys[OB_KEY_UP] = modkeys_sym_to_code(XK_Up);
+ keys[OB_KEY_DOWN] = modkeys_sym_to_code(XK_Down);
+
{
ObParseInst *i;
xmlDocPtr doc;
xmlNodePtr node;
- modkeys_startup(reconfigure);
-
/* startup the parsing so everything can register sections
of the rc */
i = parse_startup();
CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW");
CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT");
CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
+ CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
/* CREATE(net_wm_ping, "_NET_WM_PING"); */
#ifdef SYNC
CREATE(openbox_pid, "_OPENBOX_PID");
CREATE(openbox_config, "_OPENBOX_CONFIG");
- CREATE(openbox_wm_state_undecorated, "_OPENBOX_WM_STATE_UNDECORATED");
+ CREATE(openbox_wm_state_undecorated, "_OB_WM_STATE_UNDECORATED");
CREATE(openbox_control, "_OPENBOX_CONTROL");
}
Atom net_wm_user_time;
Atom net_wm_user_time_window;
Atom net_frame_extents;
+ Atom net_request_frame_extents;
/* application protocols */
/* Atom net_wm_ping; */
supported[i++] = prop_atoms.net_wm_user_time;
supported[i++] = prop_atoms.net_wm_user_time_window;
supported[i++] = prop_atoms.net_frame_extents;
+ supported[i++] = prop_atoms.net_request_frame_extents;
supported[i++] = prop_atoms.net_startup_id;
#ifdef SYNC
supported[i++] = prop_atoms.net_wm_sync_request;
SmcSaveCompleteProcMask |
SmcShutdownCancelledProcMask,
&cb, oldid, &ob_sm_id,
- SM_ERR_LEN, sm_err);
+ SM_ERR_LEN-1, sm_err);
g_free(oldid);
if (sm_conn == NULL)
ob_debug("Failed to connect to session manager: %s\n", sm_err);
if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
+ g_free(savedata);
SmcSaveYourselfDone(conn, FALSE);
}
}
static void measure_font(const RrInstance *inst, RrFont *f)
{
PangoFontMetrics *metrics;
- gchar *locale, *p;
-
- /* get the default language from the locale
- (based on gtk_get_default_language in gtkmain.c) */
- locale = g_strdup(setlocale(LC_CTYPE, NULL));
- if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
- if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
+ static PangoLanguage *lang = NULL;
+
+ if (lang == NULL) {
+#if PANGO_VERSION_CHECK(1,16,0)
+ lang = pango_language_get_default();
+#else
+ gchar *locale, *p;
+ /* get the default language from the locale
+ (based on gtk_get_default_language in gtkmain.c) */
+ locale = g_strdup(setlocale(LC_CTYPE, NULL));
+ if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
+ if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
+ lang = pango_language_from_string(locale);
+ g_free(locale);
+#endif
+ }
/* measure the ascent and descent */
- metrics = pango_context_get_metrics(inst->pango, f->font_desc,
- pango_language_from_string(locale));
+ metrics = pango_context_get_metrics(inst->pango, f->font_desc, lang);
f->ascent = pango_font_metrics_get_ascent(metrics);
f->descent = pango_font_metrics_get_descent(metrics);
pango_font_metrics_unref(metrics);
- g_free(locale);
}
RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
out->font_desc = pango_font_description_new();
out->layout = pango_layout_new(inst->pango);
out->shortcut_underline = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
+ out->shortcut_underline->start_index = 0;
+ out->shortcut_underline->end_index = 0;
attrlist = pango_attr_list_new();
/* shortcut_underline is owned by the attrlist */
break;
}
- t->font->shortcut_underline->start_index = 0;
- t->font->shortcut_underline->end_index = 0;
- /* the attributes are owned by the layout.
- re-add the attributes to the layout after changing the
- start and end index */
- attrlist = pango_layout_get_attributes(t->font->layout);
- pango_attr_list_ref(attrlist);
- pango_layout_set_attributes(t->font->layout, attrlist);
- pango_attr_list_unref(attrlist);
-
if (t->shadow_offset_x || t->shadow_offset_y) {
c.color.red = t->shadow_color->r | t->shadow_color->r << 8;
c.color.green = t->shadow_color->g | t->shadow_color->g << 8;
pango_xft_render_layout_line
(d, &c, pango_layout_get_line(t->font->layout, 0),
x * PANGO_SCALE, y * PANGO_SCALE);
+
+ if (t->shortcut) {
+ t->font->shortcut_underline->start_index = 0;
+ t->font->shortcut_underline->end_index = 0;
+ /* the attributes are owned by the layout.
+ re-add the attributes to the layout after changing the
+ start and end index */
+ attrlist = pango_layout_get_attributes(t->font->layout);
+ pango_attr_list_ref(attrlist);
+ pango_layout_set_attributes(t->font->layout, attrlist);
+ pango_attr_list_unref(attrlist);
+ }
}
winjust = RR_JUSTIFY_RIGHT;
else if (!g_ascii_strcasecmp(str, "center"))
winjust = RR_JUSTIFY_CENTER;
+ g_free(str);
}
if (menu_title_font) {
mtitlejust = RR_JUSTIFY_RIGHT;
else if (!g_ascii_strcasecmp(str, "center"))
mtitlejust = RR_JUSTIFY_CENTER;
+ g_free(str);
}
if (menu_item_font) {