X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=2f9cfb8f564c10127c5df34716885132a6bb8510;hb=096dad0c6c027100494ede811b33cb8558d32e25;hp=50a0dbeee956fc743e8a0423f75598ed5d4140e6;hpb=2f09e0ce388f63c341cb328d795766e2bd0dc24b;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 50a0dbee..2f9cfb8f 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -31,6 +31,7 @@ #include "grab.h" #include "prompt.h" #include "focus.h" +#include "focus_cycle.h" #include "stacking.h" #include "openbox.h" #include "group.h" @@ -38,7 +39,7 @@ #include "menuframe.h" #include "keyboard.h" #include "mouse.h" -#include "render/render.h" +#include "obrender/render.h" #include "gettext.h" #include "obt/display.h" #include "obt/prop.h" @@ -75,6 +76,7 @@ static RrImage *client_default_icon = NULL; static void client_get_all(ObClient *self, gboolean real); static void client_get_startup_id(ObClient *self); static void client_get_session_ids(ObClient *self); +static void client_save_app_rule_values(ObClient *self); static void client_get_area(ObClient *self); static void client_get_desktop(ObClient *self); static void client_get_state(ObClient *self); @@ -200,9 +202,10 @@ void client_manage(Window window, ObPrompt *prompt) gboolean activate = FALSE; ObAppSettings *settings; gboolean transient = FALSE; - Rect place, *monitor; + Rect place, *monitor, *allmonitors; Time launch_time, map_time; guint32 user_time; + gboolean obplaced; ob_debug("Managing window: 0x%lx", window); @@ -222,6 +225,7 @@ void client_manage(Window window, ObPrompt *prompt) self->obwin.type = OB_WINDOW_CLASS_CLIENT; self->window = window; self->prompt = prompt; + self->managed = TRUE; /* non-zero defaults */ self->wmstate = WithdrawnState; /* make sure it gets updated first time */ @@ -233,7 +237,8 @@ void client_manage(Window window, ObPrompt *prompt) ob_debug("Window type: %d", self->type); ob_debug("Window group: 0x%x", self->group?self->group->leader:0); - ob_debug("Window name: %s class: %s role: %s", self->name, self->class, self->role); + ob_debug("Window name: %s class: %s role: %s title: %s", + self->name, self->class, self->role, self->title); /* per-app settings override stuff from client_get_all, and return the settings for other uses too. the returned settings is a shallow copy, @@ -289,7 +294,9 @@ void client_manage(Window window, ObPrompt *prompt) (user_time != 0) && /* this checks for focus=false for the window */ (!settings || settings->focus != 0) && - focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE)) + focus_valid_target(self, self->desktop, + FALSE, FALSE, TRUE, FALSE, FALSE, + settings->focus == 1)) { activate = TRUE; } @@ -305,6 +312,7 @@ void client_manage(Window window, ObPrompt *prompt) /* where the frame was placed is where the window was originally */ place = self->area; monitor = screen_physical_area_monitor(screen_find_monitor(&place)); + allmonitors = screen_physical_area_all_monitors(); /* figure out placement for the window if the window is new */ if (ob_state() == OB_STATE_RUNNING) { @@ -324,9 +332,23 @@ void client_manage(Window window, ObPrompt *prompt) "program + user specified" : "BADNESS !?")))), place.width, place.height); - /* splash screens are also returned as TRUE for transient, - and so will be forced on screen below */ - transient = place_client(self, &place.x, &place.y, settings); + obplaced = place_client(self, &place.x, &place.y, settings); + + /* watch for buggy apps that ask to be placed at (0,0) when there is + a strut there */ + if (!obplaced && place.x == 0 && place.y == 0 && + /* oldschool fullscreen windows are allowed */ + !(self->decorations == 0 && (RECT_EQUAL(place, *monitor) || + RECT_EQUAL(place, *allmonitors)))) + { + Rect *r; + + r = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS, NULL); + place.x = r->x; + place.y = r->y; + ob_debug("Moving buggy app from (0,0) to (%d,%d)", r->x, r->y); + g_free(r); + } /* make sure the window is visible. */ client_find_onscreen(self, &place.x, &place.y, @@ -342,11 +364,13 @@ void client_manage(Window window, ObPrompt *prompt) it is up to the placement routines to avoid the xinerama divides) - splash screens get "transient" set to TRUE by - the place_client call + children and splash screens are forced on + screen, but i don't remember why i decided to + do that. */ ob_state() == OB_STATE_RUNNING && - (transient || + (self->type == OB_CLIENT_TYPE_DIALOG || + self->type == OB_CLIENT_TYPE_SPLASH || (!((self->positioned & USPosition) || (settings && settings->pos_given)) && client_normal(self) && @@ -356,7 +380,8 @@ void client_manage(Window window, ObPrompt *prompt) makes its fullscreen window fit the screen but it is not USSize'd or USPosition'd) */ !(self->decorations == 0 && - RECT_EQUAL(place, *monitor))))); + (RECT_EQUAL(place, *monitor) || + RECT_EQUAL(place, *allmonitors)))))); } /* if the window isn't user-sized, then make it fit inside @@ -376,7 +401,8 @@ void client_manage(Window window, ObPrompt *prompt) /* don't shrink oldschool fullscreen windows to fit inside the struts (fixes Acroread, which makes its fullscreen window fit the screen but it is not USSize'd or USPosition'd) */ - !(self->decorations == 0 && RECT_EQUAL(place, *monitor))))) + !(self->decorations == 0 && (RECT_EQUAL(place, *monitor) || + RECT_EQUAL(place, *allmonitors)))))) { Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &place); @@ -416,6 +442,8 @@ void client_manage(Window window, ObPrompt *prompt) g_free(monitor); monitor = NULL; + g_free(allmonitors); + allmonitors = NULL; ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s", activate ? "yes" : "no"); @@ -548,6 +576,8 @@ void client_unmanage(ObClient *self) mouse_grab_for_client(self, FALSE); + self->managed = FALSE; + /* remove the window from our save set, unless we are managing an internal ObPrompt window */ if (!self->prompt) @@ -788,10 +818,10 @@ static ObAppSettings *client_get_settings_state(ObClient *self) ObAppSettings *app = it->data; gboolean match = TRUE; - g_assert(app->name != NULL || app->class != NULL); + g_assert(app->name != NULL || app->class != NULL || + app->role != NULL || app->title != NULL || + (signed)app->type >= 0); - /* we know that either name or class is not NULL so it will have to - match to use the rule */ if (app->name && !g_pattern_match(app->name, strlen(self->name), self->name, NULL)) match = FALSE; @@ -803,8 +833,13 @@ static ObAppSettings *client_get_settings_state(ObClient *self) !g_pattern_match(app->role, strlen(self->role), self->role, NULL)) match = FALSE; - else if ((signed)app->type >= 0 && app->type != self->type) + else if (app->title && + !g_pattern_match(app->title, + strlen(self->title), self->title, NULL)) + match = FALSE; + else if ((signed)app->type >= 0 && app->type != self->type) { match = FALSE; + } if (match) { ob_debug("Window matching: %s", app->name); @@ -1083,6 +1118,9 @@ static void client_get_all(ObClient *self, gboolean real) /* get this early so we have it for debugging */ client_update_title(self); + /* save the values of the variables used for app rule matching */ + client_save_app_rule_values(self); + client_update_protocols(self); client_update_wmhints(self); @@ -1908,6 +1946,8 @@ void client_update_wmhints(ObClient *self) XFree(hints); } + + focus_cycle_addremove(self, TRUE); } void client_update_title(ObClient *self) @@ -2031,7 +2071,7 @@ void client_update_strut(ObClient *self) STRUT_PARTIAL_SET(strut, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - if (!STRUT_EQUAL(strut, self->strut)) { + if (!PARTIAL_STRUT_EQUAL(strut, self->strut)) { self->strut = strut; /* updating here is pointless while we're being mapped cuz we're not in @@ -2288,6 +2328,39 @@ static void client_get_session_ids(ObClient *self) } } +/*! Save the properties used for app matching rules, as seen by Openbox when + the window mapped, so that users can still access them later if the app + changes them */ +static void client_save_app_rule_values(ObClient *self) +{ + const gchar *type; + + OBT_PROP_SETS(self->window, OB_APP_ROLE, utf8, self->role); + OBT_PROP_SETS(self->window, OB_APP_NAME, utf8, self->name); + OBT_PROP_SETS(self->window, OB_APP_CLASS, utf8, self->class); + OBT_PROP_SETS(self->window, OB_APP_TITLE, utf8, self->original_title); + + switch (self->type) { + case OB_CLIENT_TYPE_NORMAL: + type = "normal"; break; + case OB_CLIENT_TYPE_DIALOG: + type = "dialog"; break; + case OB_CLIENT_TYPE_UTILITY: + type = "utility"; break; + case OB_CLIENT_TYPE_MENU: + type = "menu"; break; + case OB_CLIENT_TYPE_TOOLBAR: + type = "toolbar"; break; + case OB_CLIENT_TYPE_SPLASH: + type = "splash"; break; + case OB_CLIENT_TYPE_DESKTOP: + type = "desktop"; break; + case OB_CLIENT_TYPE_DOCK: + type = "dock"; break; + } + OBT_PROP_SETS(self->window, OB_APP_TYPE, utf8, type); +} + static void client_change_wm_state(ObClient *self) { gulong state[2]; @@ -2405,9 +2478,10 @@ gboolean client_has_parent(ObClient *self) static ObStackingLayer calc_layer(ObClient *self) { ObStackingLayer l; - Rect *monitor; + Rect *monitor, *allmonitors; monitor = screen_physical_area_monitor(client_monitor(self)); + allmonitors = screen_physical_area_all_monitors(); if (self->type == OB_CLIENT_TYPE_DESKTOP) l = OB_STACKING_LAYER_DESKTOP; @@ -2421,7 +2495,8 @@ static ObStackingLayer calc_layer(ObClient *self) */ (self->decorations == 0 && !(self->max_horz && self->max_vert) && - RECT_EQUAL(self->area, *monitor))) && + (RECT_EQUAL(self->area, *monitor) || + RECT_EQUAL(self->area, *allmonitors)))) && /* you are fullscreen while you or your children are focused.. */ (client_focused(self) || client_search_focus_tree(self) || /* you can be fullscreen if you're on another desktop */ @@ -2437,6 +2512,7 @@ static ObStackingLayer calc_layer(ObClient *self) else l = OB_STACKING_LAYER_NORMAL; g_free(monitor); + g_free(allmonitors); return l; } @@ -3073,6 +3149,9 @@ void client_fullscreen(ObClient *self, gboolean fs) if (fs) { self->pre_fullscreen_area = self->area; + self->pre_fullscreen_max_horz = self->max_horz; + self->pre_fullscreen_max_vert = self->max_vert; + /* if the window is maximized, its area isn't all that meaningful. save its premax area instead. */ if (self->max_horz) { @@ -3094,6 +3173,17 @@ void client_fullscreen(ObClient *self, gboolean fs) g_assert(self->pre_fullscreen_area.width > 0 && self->pre_fullscreen_area.height > 0); + self->max_horz = self->pre_fullscreen_max_horz; + self->max_vert = self->pre_fullscreen_max_vert; + if (self->max_horz) { + self->pre_max_area.x = self->pre_fullscreen_area.x; + self->pre_max_area.width = self->pre_fullscreen_area.width; + } + if (self->max_vert) { + self->pre_max_area.y = self->pre_fullscreen_area.y; + self->pre_max_area.height = self->pre_fullscreen_area.height; + } + x = self->pre_fullscreen_area.x; y = self->pre_fullscreen_area.y; w = self->pre_fullscreen_area.width; @@ -3136,7 +3226,7 @@ static void client_iconify_recursive(ObClient *self, self->iconic = iconic; /* update the focus lists.. iconic windows go to the bottom of - the list */ + the list. this will also call focus_cycle_addremove(). */ focus_order_to_bottom(self); changed = TRUE; @@ -3148,9 +3238,10 @@ static void client_iconify_recursive(ObClient *self, self->desktop != DESKTOP_ALL) client_set_desktop(self, screen_desktop, FALSE, FALSE); - /* this puts it after the current focused window */ - focus_order_remove(self); - focus_order_add_new(self); + /* this puts it after the current focused window, this will + also cause focus_cycle_addremove() to be called for the + client */ + focus_order_like_new(self); changed = TRUE; } @@ -3483,6 +3574,8 @@ static void client_set_desktop_recursive(ObClient *self, /* the new desktop's geometry may be different, so we may need to resize, for example if we are maximized */ client_reconfigure(self, FALSE); + + focus_cycle_addremove(self, FALSE); } /* move all transients */ @@ -3498,6 +3591,8 @@ void client_set_desktop(ObClient *self, guint target, { self = client_search_top_direct_parent(self); client_set_desktop_recursive(self, target, donthide, dontraise); + + focus_cycle_addremove(NULL, TRUE); } gboolean client_is_direct_child(ObClient *parent, ObClient *child) @@ -3711,6 +3806,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) client_hilite(self, demands_attention); client_change_state(self); /* change the hint to reflect these changes */ + + focus_cycle_addremove(self, TRUE); } ObClient *client_focus_target(ObClient *self) @@ -3817,7 +3914,8 @@ static void client_present(ObClient *self, gboolean here, gboolean raise, } /* this function exists to map to the net_active_window message in the ewmh */ -void client_activate(ObClient *self, gboolean desktop, gboolean raise, +void client_activate(ObClient *self, gboolean desktop, + gboolean here, gboolean raise, gboolean unshade, gboolean user) { if ((user && (desktop || @@ -3825,7 +3923,7 @@ void client_activate(ObClient *self, gboolean desktop, gboolean raise, self->desktop == screen_desktop)) || client_can_steal_focus(self, event_curtime, CurrentTime)) { - client_present(self, FALSE, raise, unshade); + client_present(self, here, raise, unshade); } else client_hilite(self, TRUE); @@ -4122,39 +4220,26 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, gint *dest, gboolean *near_edge) { GList *it; - Rect *a, *mon; + Rect *a; Rect dock_area; gint edge; + guint i; a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS, &self->frame->area); - mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, - &self->frame->area); switch (dir) { case OB_DIRECTION_NORTH: - if (my_head >= RECT_TOP(*mon) + 1) - edge = RECT_TOP(*mon) - 1; - else - edge = RECT_TOP(*a) - 1; + edge = RECT_TOP(*a) - 1; break; case OB_DIRECTION_SOUTH: - if (my_head <= RECT_BOTTOM(*mon) - 1) - edge = RECT_BOTTOM(*mon) + 1; - else - edge = RECT_BOTTOM(*a) + 1; + edge = RECT_BOTTOM(*a) + 1; break; case OB_DIRECTION_EAST: - if (my_head <= RECT_RIGHT(*mon) - 1) - edge = RECT_RIGHT(*mon) + 1; - else - edge = RECT_RIGHT(*a) + 1; + edge = RECT_RIGHT(*a) + 1; break; case OB_DIRECTION_WEST: - if (my_head >= RECT_LEFT(*mon) + 1) - edge = RECT_LEFT(*mon) - 1; - else - edge = RECT_LEFT(*a) - 1; + edge = RECT_LEFT(*a) - 1; break; default: g_assert_not_reached(); @@ -4163,28 +4248,43 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, *dest = edge; *near_edge = TRUE; - for (it = client_list; it; it = g_list_next(it)) { - ObClient *cur = it->data; + /* search for edges of monitors */ + for (i = 0; i < screen_num_monitors; ++i) { + Rect *area = screen_area(self->desktop, i, NULL); + detect_edge(*area, dir, my_head, my_size, my_edge_start, + my_edge_size, dest, near_edge); + g_free(area); + } + + /* search for edges of clients */ + if (((dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH) && + !self->max_vert) || + ((dir == OB_DIRECTION_EAST || dir == OB_DIRECTION_WEST) && + !self->max_horz)) + { + for (it = client_list; it; it = g_list_next(it)) { + ObClient *cur = it->data; - /* skip windows to not bump into */ - if (cur == self) - continue; - if (cur->iconic) - continue; - if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && - cur->desktop != screen_desktop) - continue; + /* skip windows to not bump into */ + if (cur == self) + continue; + if (cur->iconic) + continue; + if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && + cur->desktop != screen_desktop) + continue; - ob_debug("trying window %s", cur->title); + ob_debug("trying window %s", cur->title); - detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start, + detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start, + my_edge_size, dest, near_edge); + } + dock_get_area(&dock_area); + detect_edge(dock_area, dir, my_head, my_size, my_edge_start, my_edge_size, dest, near_edge); } - dock_get_area(&dock_area); - detect_edge(dock_area, dir, my_head, my_size, my_edge_start, - my_edge_size, dest, near_edge); + g_free(a); - g_free(mon); } void client_find_move_directional(ObClient *self, ObDirection dir,