X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=88eecf1443db161f79d076aca4ddcd6262fe7bce;hb=d3d4aa29871111737a4f6985da695c8688a05270;hp=2b30bddf8686dad04f09a27e890e02c019b0f4cf;hpb=60565bcba8bd5e42f82659b4aa641b05c5ec70a0;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 2b30bddf..88eecf14 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,7 +1,7 @@ /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- client.c for the Openbox window manager - Copyright (c) 2004 Mikael Magnusson + Copyright (c) 2006 Mikael Magnusson Copyright (c) 2003 Ben Jansens This program is free software; you can redistribute it and/or modify @@ -126,7 +126,7 @@ void client_set_list() windows = NULL; PROP_SETA32(RootWindow(ob_display, ob_screen), - net_client_list, window, (guint32*)windows, size); + net_client_list, window, (gulong*)windows, size); if (windows) g_free(windows); @@ -204,6 +204,33 @@ void client_manage_all() XFree(children); } +static ObAppSettings *get_settings(ObClient *client) +{ + GSList *a = config_per_app_settings; + + while (a) { + ObAppSettings *app = (ObAppSettings *) a->data; + + if ( + (app->name && !app->class && !strcmp(app->name, client->name)) + || (app->class && !app->name && !strcmp(app->class, client->class)) + || (app->class && app->name && !strcmp(app->class, client->class) + && !strcmp(app->name, client->name)) + ) { + ob_debug("Window matching: %s\n", app->name); + /* Match if no role was specified in the per app setting, or if the + * string matches the beginning of the role, since apps like to set + * the role to things like browser-window-23c4b2f */ + if (!app->role + || !strncmp(app->role, client->role, strlen(app->role))) + return app; + } + + a = a->next; + } + return NULL; +} + void client_manage(Window window) { ObClient *self; @@ -212,6 +239,7 @@ void client_manage(Window window) XSetWindowAttributes attrib_set; XWMHints *wmhint; gboolean activate = FALSE; + ObAppSettings *settings; grab_server(TRUE); @@ -292,12 +320,59 @@ void client_manage(Window window) client_apply_startup_state(self); + /* get and set application level settings */ + settings = get_settings(self); + stacking_add(CLIENT_AS_WINDOW(self)); client_restore_session_stacking(self); + if (settings) { + /* Don't worry, we won't actually both shade and undecorate the + * window when push comes to shove. */ + if (settings->shade != -1) + client_shade(self, settings->shade); + if (settings->decor != -1) + client_set_undecorated(self, !settings->decor); + if (settings->iconic != -1) + client_iconify(self, settings->iconic, FALSE); + if (settings->skip_pager != -1) { + self->skip_pager = !!settings->skip_pager; + client_change_state(self); + } + if (settings->skip_taskbar != -1) { + self->skip_taskbar = !!settings->skip_taskbar; + client_change_state(self); + } + + /* 1 && -1 shouldn't be possible by the code in config.c */ + if (settings->max_vert == 1 && settings->max_horz == 1) + client_maximize(self, TRUE, 0, TRUE); + else if (settings->max_vert == 0 && settings->max_horz == 0) + client_maximize(self, FALSE, 0, TRUE); + else if (settings->max_vert == 1 && settings->max_horz == 0) { + client_maximize(self, TRUE, 2, TRUE); + client_maximize(self, FALSE, 1, TRUE); + } else if (settings->max_vert == 0 && settings->max_horz == 1) { + client_maximize(self, TRUE, 1, TRUE); + client_maximize(self, FALSE, 2, TRUE); + } + + if (settings->fullscreen != -1) + client_fullscreen(self, !!settings->fullscreen, TRUE); + + if (settings->desktop < screen_num_desktops + || settings->desktop == DESKTOP_ALL) + client_set_desktop(self, settings->desktop, TRUE); + + if (settings->layer > -2 && settings->layer < 2) + client_set_layer(self, settings->layer); + + } + /* focus the new window? */ if (ob_state() != OB_STATE_STARTING && - (config_focus_new || client_search_focus_parent(self)) && + (config_focus_new || client_search_focus_parent(self)) || + (settings && settings->focus == TRUE) && /* 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 */ @@ -341,19 +416,29 @@ void client_manage(Window window) if (ob_state() == OB_STATE_RUNNING) { gint x = self->area.x, ox = x; gint y = self->area.y, oy = y; + gboolean transient; - place_client(self, &x, &y); + transient = place_client(self, &x, &y, settings); - /* make sure the window is visible. */ client_find_onscreen(self, &x, &y, self->frame->area.width, self->frame->area.height, /* non-normal clients has less rules, and - windows that are being restored from a session - do also. we can assume you want it back where - you saved it */ - client_normal(self) && !self->session); + windows that are being restored from a + session do also. we can assume you want + it back where you saved it. Clients saying + they placed themselves are subjected to + harder rules, ones that are placed by + place.c or by the user are allowed partially + off-screen and on xinerama divides (ie, + it is up to the placement routines to avoid + the xinerama divides) */ + transient || + (((self->positioned & PPosition) && + !(self->positioned & USPosition)) && + client_normal(self) && + !self->session)); if (x != ox || y != oy) client_move(self, x, y); } @@ -544,7 +629,7 @@ static void client_restore_session_state(ObClient *self) self->session = it->data; RECT_SET_POINT(self->area, self->session->x, self->session->y); - self->positioned = TRUE; + self->positioned = PPosition; if (self->session->w > 0) self->area.width = self->session->w; if (self->session->h > 0) @@ -613,8 +698,8 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, /* XXX watch for xinerama dead areas */ /* This makes sure windows aren't entirely outside of the screen so you * can't see them at all */ - a = screen_area(self->desktop); if (client_normal(self)) { + 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) @@ -626,16 +711,16 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, } /* This here doesn't let windows even a pixel outside the screen, - * not applied to all windows. Not sure if it's going to stay at all. - * I wonder if disabling this will break struts somehow? Let's find out. */ - if (0 && rude) { + * when called from client_manage, programs placing themselves are + * forced completely onscreen, while things like + * xterm -geometry resolution-width/2 will work fine. Trying to + * place it completely offscreen will be handled in the above code. + * Sorry for this confused comment, i am tired. */ + if (rude) { /* avoid the xinerama monitor divide while we're at it, * remember to fix the placement stuff to avoid it also and * then remove this XXX */ a = screen_physical_area_monitor(client_monitor(self)); - /* this is ben's MOZILLA BITCHSLAP. "oh ya it fucking feels good. - Java can suck it too." */ - /* dont let windows map/move into the strut unless they are bigger than the available area */ if (w <= a->width) { @@ -1119,7 +1204,7 @@ void client_update_normal_hints(ObClient *self) /* normal windows can't request placement! har har if (!client_normal(self)) */ - self->positioned = !!(size.flags & (PPosition|USPosition)); + self->positioned = (size.flags & (PPosition|USPosition)); if (size.flags & PWinGravity) { self->gravity = size.win_gravity; @@ -1153,7 +1238,7 @@ void client_update_normal_hints(ObClient *self) if (size.flags & PBaseSize) SIZE_SET(self->base_size, size.base_width, size.base_height); - if (size.flags & PResizeInc) + if (size.flags & PResizeInc && size.width_inc && size.height_inc) SIZE_SET(self->size_inc, size.width_inc, size.height_inc); } } @@ -1163,7 +1248,7 @@ void client_setup_decor_and_functions(ObClient *self) /* start with everything (cept fullscreen) */ self->decorations = (OB_FRAME_DECOR_TITLEBAR | - (ob_rr_theme->show_handle ? OB_FRAME_DECOR_HANDLE : 0) | + OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS | OB_FRAME_DECOR_BORDER | OB_FRAME_DECOR_ICON | @@ -1219,8 +1304,12 @@ void client_setup_decor_and_functions(ObClient *self) if (! ((self->mwmhints.decorations & OB_MWM_DECOR_HANDLE) || (self->mwmhints.decorations & OB_MWM_DECOR_TITLE))) /* if the mwm hints request no handle or title, then all - decorations are disabled */ - self->decorations = 0; + decorations are disabled, but keep the border if that's + specified */ + if (self->mwmhints.decorations & OB_MWM_DECOR_BORDER) + self->decorations = OB_FRAME_DECOR_BORDER; + else + self->decorations = 0; } } @@ -1292,7 +1381,7 @@ void client_setup_decor_and_functions(ObClient *self) static void client_change_allowed_actions(ObClient *self) { - guint32 actions[9]; + gulong actions[9]; gint num = 0; /* desktop windows are kept on all desktops */ @@ -1454,7 +1543,8 @@ void client_update_title(ObClient *self) /* try netwm */ if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) { /* try old x stuff */ - if (!PROP_GETS(self->window, wm_name, locale, &data)) { + if (!(PROP_GETS(self->window, wm_name, locale, &data) + || PROP_GETS(self->window, wm_name, utf8, &data))) { // http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html if (self->transient) { data = g_strdup(""); @@ -1464,35 +1554,39 @@ void client_update_title(ObClient *self) } } - /* did the title change? then reset the title_count */ - if (old_title && 0 != strncmp(old_title, data, strlen(data))) - self->title_count = 1; + if (config_title_number) { - /* look for duplicates and append a number */ - nums = 0; - for (it = client_list; it; it = g_list_next(it)) - if (it->data != self) { - ObClient *c = it->data; - if (0 == strncmp(c->title, data, strlen(data))) - nums |= 1 << c->title_count; - } - /* find first free number */ - for (i = 1; i <= 32; ++i) - if (!(nums & (1 << i))) { - if (self->title_count == 1 || i == 1) - self->title_count = i; - break; + /* 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 = g_list_next(it)) + if (it->data != self) { + ObClient *c = it->data; + if (0 == strncmp(c->title, data, strlen(data))) + nums |= 1 << c->title_count; + } + /* find first free number */ + for (i = 1; i <= 32; ++i) + if (!(nums & (1 << i))) { + if (self->title_count == 1 || i == 1) + self->title_count = i; + break; + } + /* dont display the number for the first window */ + if (self->title_count > 1) { + gchar *ndata; + ndata = g_strdup_printf("%s - [%u]", data, self->title_count); + g_free(data); + data = ndata; } - /* dont display the number for the first window */ - if (self->title_count > 1) { - gchar *ndata; - ndata = g_strdup_printf("%s - [%u]", data, self->title_count); - g_free(data); - data = ndata; - } + } else + self->title_count = 1; - PROP_SETS(self->window, net_wm_visible_name, data); no_number: + PROP_SETS(self->window, net_wm_visible_name, data); self->title = data; if (self->frame) @@ -1508,12 +1602,15 @@ no_number: /* try netwm */ if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data)) /* try old x stuff */ - if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) { + if (!(PROP_GETS(self->window, wm_icon_name, locale, &data) + || PROP_GETS(self->window, wm_icon_name, utf8, &data))) { data = g_strdup(self->title); read_title = FALSE; } - /* append the title count, dont display the number for the first window */ + /* append the title count, dont display the number for the first window. + * We don't need to check for config_title_number here since title_count + * is not set above 1 then. */ if (read_title && self->title_count > 1) { gchar *vdata, *ndata; ndata = g_strdup_printf(" - [%u]", self->title_count); @@ -1707,8 +1804,8 @@ void client_update_icons(ObClient *self) static void client_change_state(ObClient *self) { - guint32 state[2]; - guint32 netstate[11]; + gulong state[2]; + gulong netstate[11]; guint num; state[0] = self->wmstate; @@ -1796,9 +1893,8 @@ static ObStackingLayer calc_layer(ObClient *self) else if (self->type == OB_CLIENT_TYPE_DESKTOP) l = OB_STACKING_LAYER_DESKTOP; else if (self->type == OB_CLIENT_TYPE_DOCK) { - if (self->above) l = OB_STACKING_LAYER_DOCK_ABOVE; - else if (self->below) l = OB_STACKING_LAYER_DOCK_BELOW; - else l = OB_STACKING_LAYER_DOCK_NORMAL; + if (self->below) l = OB_STACKING_LAYER_NORMAL; + else l = OB_STACKING_LAYER_ABOVE; } else if (self->above) l = OB_STACKING_LAYER_ABOVE; else if (self->below) l = OB_STACKING_LAYER_BELOW; @@ -1953,35 +2049,16 @@ void client_configure_full(ObClient *self, ObCorner anchor, /* set the size and position if fullscreen */ if (self->fullscreen) { -#ifdef VIDMODE - gint dot; - XF86VidModeModeLine mode; -#endif Rect *a; guint i; i = client_monitor(self); a = screen_physical_area_monitor(i); -#ifdef VIDMODE - if (i == 0 && /* primary head */ - extensions_vidmode && - XF86VidModeGetViewPort(ob_display, ob_screen, &x, &y) && - /* get the mode last so the mode.privsize isnt freed incorrectly */ - XF86VidModeGetModeLine(ob_display, ob_screen, &dot, &mode)) { - x += a->x; - y += a->y; - w = mode.hdisplay; - h = mode.vdisplay; - if (mode.privsize) XFree(mode.private); - } else -#endif - { - x = a->x; - y = a->y; - w = a->width; - h = a->height; - } + x = a->x; + y = a->y; + w = a->width; + h = a->height; user = FALSE; /* ignore that increment etc shit when in fullscreen */ } else { @@ -2265,12 +2342,6 @@ static void client_iconify_recursive(ObClient *self, focus_order_remove(self); focus_order_add_new(self); - /* this is here cuz with the VIDMODE extension, the viewport can - change while a fullscreen window is iconic, and when it - uniconifies, it would be nice if it did so to the new position - of the viewport */ - client_reconfigure(self); - changed = TRUE; } } @@ -2778,13 +2849,15 @@ gboolean client_focus(ObClient *self) return TRUE; } +/* Used when the current client is closed, focus_last will then prevent + * focus from going to the mouse pointer */ void client_unfocus(ObClient *self) { if (focus_client == self) { #ifdef DEBUG_FOCUS ob_debug("client_unfocus for %lx\n", self->window); #endif - focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING); + focus_fallback(OB_FOCUS_FALLBACK_CLOSED); } } @@ -3010,6 +3083,13 @@ void client_set_undecorated(ObClient *self, gboolean undecorated) if (self->undecorated != undecorated) { self->undecorated = undecorated; client_setup_decor_and_functions(self); + /* Make sure the client knows it might have moved. Maybe there is a + * better way of doing this so only one client_configure is sent, but + * since 125 of these are sent per second when moving the window (with + * user = FALSE) i doubt it matters much. + */ + client_configure(self, OB_CORNER_TOPLEFT, self->area.x, self->area.y, + self->area.width, self->area.height, TRUE, TRUE); client_change_state(self); /* reflect this in the state hints */ } } @@ -3137,11 +3217,30 @@ void client_update_sm_client_id(ObClient *self) &self->sm_client_id); } +#define WANT_EDGE(cur, c) \ + if(cur == c) \ + continue; \ + if(!client_normal(cur)) \ + continue; \ + if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \ + continue; \ + if(cur->iconic) \ + continue; \ + if(cur->layer < c->layer && !config_resist_layers_below) \ + continue; + +#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \ + if ((his_edge_start >= my_edge_start && \ + his_edge_start <= my_edge_end) || \ + (my_edge_start >= his_edge_start && \ + my_edge_start <= his_edge_end)) \ + dest = his_offset; + /* finds the nearest edge in the given direction from the current client * note to self: the edge is the -frame- edge (the actual one), not the * client edge. */ -gint client_directional_edge_search(ObClient *c, ObDirection dir) +gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) { gint dest, monitor_dest; gint my_edge_start, my_edge_end, my_offset; @@ -3158,11 +3257,11 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) case OB_DIRECTION_NORTH: my_edge_start = c->frame->area.x; my_edge_end = c->frame->area.x + c->frame->area.width; - my_offset = c->frame->area.y; + my_offset = c->frame->area.y + (hang ? c->frame->area.height : 0); /* default: top of screen */ - dest = a->y; - monitor_dest = monitor->y; + dest = a->y + (hang ? c->frame->area.height : 0); + monitor_dest = monitor->y + (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3172,45 +3271,31 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; - if(cur == c) - continue; - if(!client_normal(cur)) - continue; - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) - continue; - if(cur->iconic) - continue; - if(cur->layer < c->layer && !config_resist_layers_below) - continue; + WANT_EDGE(cur, c) his_edge_start = cur->frame->area.x; his_edge_end = cur->frame->area.x + cur->frame->area.width; - his_offset = cur->frame->area.y + cur->frame->area.height; + his_offset = cur->frame->area.y + + (hang ? 0 : cur->frame->area.height); if(his_offset + 1 > my_offset) continue; if(his_offset < dest) continue; - - if(his_edge_start >= my_edge_start && - his_edge_start <= my_edge_end) - dest = his_offset; - - if(my_edge_start >= his_edge_start && - my_edge_start <= his_edge_end) - dest = his_offset; + HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) } break; case OB_DIRECTION_SOUTH: my_edge_start = c->frame->area.x; my_edge_end = c->frame->area.x + c->frame->area.width; - my_offset = c->frame->area.y + c->frame->area.height; + my_offset = c->frame->area.y + (hang ? 0 : c->frame->area.height); /* default: bottom of screen */ - dest = a->y + a->height; - monitor_dest = monitor->y + monitor->height; + dest = a->y + a->height - (hang ? c->frame->area.height : 0); + monitor_dest = monitor->y + monitor->height - + (hang ? c->frame->area.height : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset < monitor_dest) @@ -3220,20 +3305,12 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; - if(cur == c) - continue; - if(!client_normal(cur)) - continue; - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) - continue; - if(cur->iconic) - continue; - if(cur->layer < c->layer && !config_resist_layers_below) - continue; + WANT_EDGE(cur, c) his_edge_start = cur->frame->area.x; his_edge_end = cur->frame->area.x + cur->frame->area.width; - his_offset = cur->frame->area.y; + his_offset = cur->frame->area.y + + (hang ? cur->frame->area.height : 0); if(his_offset - 1 < my_offset) @@ -3241,25 +3318,18 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) if(his_offset > dest) continue; - - if(his_edge_start >= my_edge_start && - his_edge_start <= my_edge_end) - dest = his_offset; - - if(my_edge_start >= his_edge_start && - my_edge_start <= his_edge_end) - dest = his_offset; + HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) } break; case OB_DIRECTION_WEST: my_edge_start = c->frame->area.y; my_edge_end = c->frame->area.y + c->frame->area.height; - my_offset = c->frame->area.x; + my_offset = c->frame->area.x + (hang ? c->frame->area.width : 0); /* default: leftmost egde of screen */ - dest = a->x; - monitor_dest = monitor->x; + dest = a->x + (hang ? c->frame->area.width : 0); + monitor_dest = monitor->x + (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset > monitor_dest) @@ -3269,46 +3339,31 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; - if(cur == c) - continue; - if(!client_normal(cur)) - continue; - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) - continue; - if(cur->iconic) - continue; - if(cur->layer < c->layer && !config_resist_layers_below) - continue; + WANT_EDGE(cur, c) his_edge_start = cur->frame->area.y; his_edge_end = cur->frame->area.y + cur->frame->area.height; - his_offset = cur->frame->area.x + cur->frame->area.width; + his_offset = cur->frame->area.x + + (hang ? 0 : cur->frame->area.width); if(his_offset + 1 > my_offset) continue; - + if(his_offset < dest) continue; - - if(his_edge_start >= my_edge_start && - his_edge_start <= my_edge_end) - dest = his_offset; - - if(my_edge_start >= his_edge_start && - my_edge_start <= his_edge_end) - dest = his_offset; - + HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) } - break; + break; case OB_DIRECTION_EAST: my_edge_start = c->frame->area.y; my_edge_end = c->frame->area.y + c->frame->area.height; - my_offset = c->frame->area.x + c->frame->area.width; + my_offset = c->frame->area.x + (hang ? 0 : c->frame->area.width); /* default: rightmost edge of screen */ - dest = a->x + a->width; - monitor_dest = monitor->x + monitor->width; + dest = a->x + a->width - (hang ? c->frame->area.width : 0); + monitor_dest = monitor->x + monitor->width - + (hang ? c->frame->area.width : 0); /* if the monitor edge comes before the screen edge, */ /* use that as the destination instead. (For xinerama) */ if (monitor_dest != dest && my_offset < monitor_dest) @@ -3318,35 +3373,20 @@ gint client_directional_edge_search(ObClient *c, ObDirection dir) gint his_edge_start, his_edge_end, his_offset; ObClient *cur = it->data; - if(cur == c) - continue; - if(!client_normal(cur)) - continue; - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) - continue; - if(cur->iconic) - continue; - if(cur->layer < c->layer && !config_resist_layers_below) - continue; + WANT_EDGE(cur, c) his_edge_start = cur->frame->area.y; his_edge_end = cur->frame->area.y + cur->frame->area.height; - his_offset = cur->frame->area.x; + his_offset = cur->frame->area.x + + (hang ? cur->frame->area.width : 0); if(his_offset - 1 < my_offset) continue; if(his_offset > dest) continue; - - if(his_edge_start >= my_edge_start && - his_edge_start <= my_edge_end) - dest = his_offset; - - if(my_edge_start >= his_edge_start && - my_edge_start <= his_edge_end) - dest = his_offset; + HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) } break; case OB_DIRECTION_NORTHEAST: