X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=961c6bbf3c696c2bad8498984a88857cb15ceb10;hb=0964b804a135243968de22695b953f19f9e8b9d1;hp=e0dc3f876761e0e8e67e7a670241cfd4e6a38949;hpb=067776e783fc0cb4a731c8ea226c8b6b3c50f053;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index e0dc3f87..961c6bbf 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -8,6 +8,7 @@ #include "prop.h" #include "extensions.h" #include "frame.h" +#include "session.h" #include "event.h" #include "grab.h" #include "focus.h" @@ -17,6 +18,8 @@ #include "group.h" #include "config.h" #include "menu.h" +#include "keyboard.h" +#include "mouse.h" #include "render/render.h" #include @@ -43,6 +46,8 @@ static void client_showhide(ObClient *self); static void client_change_allowed_actions(ObClient *self); static void client_change_state(ObClient *self); static void client_apply_startup_state(ObClient *self); +static void client_restore_session_state(ObClient *self); +static void client_restore_session_stacking(ObClient *self); void client_startup() { @@ -231,7 +236,11 @@ void client_manage(Window window) self = g_new(ObClient, 1); self->obwin.type = Window_Client; self->window = window; + client_get_all(self); + client_restore_session_state(self); + + client_change_state(self); /* remove the client's border (and adjust re gravity) */ client_toggle_border(self, FALSE); @@ -249,14 +258,11 @@ void client_manage(Window window) grab_server(FALSE); - /* add to client list/map */ - client_list = g_list_append(client_list, self); - g_hash_table_insert(window_map, &self->window, self); - /* update the focus lists */ focus_order_add_new(self); stacking_add(CLIENT_AS_WINDOW(self)); + client_restore_session_stacking(self); /* focus the new window? */ if (ob_state() != OB_STATE_STARTING && config_focus_new && @@ -300,8 +306,7 @@ void client_manage(Window window) dispatch_client(Event_Client_New, self, 0, 0); /* make sure the window is visible */ - if (!(self->strut.left || self->strut.right || - self->strut.top || self->strut.bottom)) + if (ob_state() == OB_STATE_RUNNING) client_move_onscreen(self, TRUE); screen_update_areas(); @@ -320,9 +325,16 @@ void client_manage(Window window) if (screen_showing_desktop) screen_show_desktop(FALSE); + /* add to client list/map */ + client_list = g_list_append(client_list, self); + g_hash_table_insert(window_map, &self->window, self); + /* update the list hints */ client_set_list(); + keyboard_grab_for_client(self, TRUE); + mouse_grab_for_client(self, TRUE); + dispatch_client(Event_Client_Mapped, self, 0, 0); ob_debug("Managed window 0x%lx (%s)\n", window, self->class); @@ -351,6 +363,9 @@ void client_unmanage(ObClient *self) dispatch_client(Event_Client_Destroy, self, 0, 0); g_assert(self != NULL); + keyboard_grab_for_client(self, FALSE); + mouse_grab_for_client(self, FALSE); + /* remove the window from our save set */ XChangeSaveSet(ob_display, self->window, SetModeDelete); @@ -429,6 +444,7 @@ void client_unmanage(ObClient *self) unmapping/mapping */ PROP_ERASE(self->window, net_wm_desktop); PROP_ERASE(self->window, net_wm_state); + PROP_ERASE(self->window, wm_state); } else { /* if we're left in an iconic state, the client wont be mapped. this is bad, since we will no longer be managing the window on restart */ @@ -456,12 +472,66 @@ void client_unmanage(ObClient *self) client_set_list(); } +static void client_restore_session_state(ObClient *self) +{ + GList *it; + + if (!(it = session_state_find(self))) + return; + + self->session = it->data; + + RECT_SET(self->area, self->session->x, self->session->y, + self->session->w, self->session->h); + self->positioned = TRUE; + XResizeWindow(ob_display, self->window, + self->session->w, self->session->h); + + self->desktop = (self->session->desktop == DESKTOP_ALL ? + self->session->desktop : + MIN(screen_num_desktops - 1, self->session->desktop)); + PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop); + + self->shaded = self->session->shaded; + self->iconic = self->session->iconic; + self->skip_pager = self->session->skip_pager; + self->skip_taskbar = self->session->skip_taskbar; + self->fullscreen = self->session->fullscreen; + self->above = self->session->above; + self->below = self->session->below; + self->max_horz = self->session->max_horz; + self->max_vert = self->session->max_vert; +} + +static void client_restore_session_stacking(ObClient *self) +{ + GList *it; + + if (!self->session) return; + + it = g_list_find(session_saved_state, self->session); + for (it = g_list_previous(it); it; it = g_list_previous(it)) { + GList *cit; + + for (cit = client_list; cit; cit = g_list_next(cit)) + if (session_state_cmp(it->data, cit->data)) + break; + if (cit) { + client_calc_layer(self); + stacking_below(CLIENT_AS_WINDOW(self), + CLIENT_AS_WINDOW(cit->data)); + break; + } + } +} + void client_move_onscreen(ObClient *self, gboolean rude) { int x = self->area.x; int y = self->area.y; if (client_find_onscreen(self, &x, &y, - self->area.width, self->area.height, rude)) { + self->frame->area.width, + self->frame->area.height, rude)) { client_configure(self, OB_CORNER_TOPLEFT, x, y, self->area.width, self->area.height, TRUE, TRUE); @@ -480,13 +550,13 @@ gboolean client_find_onscreen(ObClient *self, int *x, int *y, int w, int h, /* XXX watch for xinerama dead areas */ a = screen_area(self->desktop); - if (*x >= a->x + a->width - 1) + if (!self->strut.right && *x >= a->x + a->width - 1) *x = a->x + a->width - self->frame->area.width; - if (*y >= a->y + a->height - 1) + if (!self->strut.bottom && *y >= a->y + a->height - 1) *y = a->y + a->height - self->frame->area.height; - if (*x + self->frame->area.width - 1 < a->x) + if (!self->strut.left && *x + self->frame->area.width - 1 < a->x) *x = a->x; - if (*y + self->frame->area.height - 1 < a->y) + if (!self->strut.top && *y + self->frame->area.height - 1 < a->y) *y = a->y; if (rude) { @@ -496,13 +566,13 @@ gboolean client_find_onscreen(ObClient *self, int *x, int *y, int w, int h, /* dont let windows map/move into the strut unless they are bigger than the available area */ if (w <= a->width) { - if (*x < a->x) *x = a->x; - if (*x + w > a->x + a->width) + if (!self->strut.left && *x < a->x) *x = a->x; + if (!self->strut.right && *x + w > a->x + a->width) *x = a->x + a->width - w; } if (h <= a->height) { - if (*y < a->y) *y = a->y; - if (*y + h > a->y + a->height) + if (!self->strut.top && *y < a->y) *y = a->y; + if (!self->strut.bottom && *y + h > a->y + a->height) *y = a->y + a->height - h; } } @@ -587,6 +657,7 @@ static void client_get_all(ObClient *self) /* defaults */ self->frame = NULL; + self->session = NULL; self->title = self->icon_title = NULL; self->title_count = 1; self->name = self->class = self->role = NULL; @@ -625,8 +696,6 @@ static void client_get_all(ObClient *self) client_update_class(self); client_update_strut(self); client_update_icons(self); - - client_change_state(self); } static void client_get_area(ObClient *self) @@ -672,7 +741,6 @@ static void client_get_desktop(ObClient *self) if (!trdesk) /* defaults to the current desktop */ self->desktop = screen_desktop; - } if (self->desktop != d) { /* set the desktop hint, to make sure that it always exists */ @@ -1066,7 +1134,7 @@ void client_setup_decor_and_functions(ObClient *self) /* finally, the user can have requested no decorations, which overrides everything */ if (!self->decorate) - self->decorations = 0; + self->decorations = OB_FRAME_DECOR_BORDER; /* if we don't have a titlebar, then we cannot shade! */ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR)) @@ -1083,13 +1151,8 @@ void client_setup_decor_and_functions(ObClient *self) client_change_allowed_actions(self); if (self->frame) { - /* this makes sure that these windows appear on all desktops */ - if (self->type == OB_CLIENT_TYPE_DESKTOP && - self->desktop != DESKTOP_ALL) - client_set_desktop(self, DESKTOP_ALL, FALSE); - - /* adjust the client's decorations, etc. */ - client_reconfigure(self); + /* adjust the client's decorations, etc. */ + client_reconfigure(self); } else { /* this makes sure that these windows appear on all desktops */ if (self->type == OB_CLIENT_TYPE_DESKTOP && @@ -1212,9 +1275,6 @@ void client_update_wmhints(ObClient *self) } } - /* the WM_HINTS can contain an icon */ - client_update_icons(self); - /* because the self->transient flag wont change from this call, we don't need to update the window's type and such, only its transient_for, and the transients lists of other windows in @@ -1222,6 +1282,9 @@ void client_update_wmhints(ObClient *self) client_update_transient_for(self); } + /* the WM_HINTS can contain an icon */ + client_update_icons(self); + XFree(hints); } @@ -1344,20 +1407,35 @@ void client_update_strut(ObClient *self) { guint num; guint32 *data; + gboolean got = FALSE; + + if (PROP_GETA32(self->window, net_wm_strut_partial, cardinal, + &data, &num)) { + if (num == 12) { + got = TRUE; + STRUT_PARTIAL_SET(self->strut, + data[0], data[2], data[1], data[3], + data[4], data[5], data[8], data[9], + data[6], data[7], data[10], data[11]); + } + g_free(data); + } - if (!PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) { - STRUT_SET(self->strut, 0, 0, 0, 0); - } else { + if (!got && + PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) { if (num == 4) { - g_message("new strut: %d %d %d %d", - data[0], data[2], data[1], data[3]); - STRUT_SET(self->strut, data[0], data[2], data[1], data[3]); + got = TRUE; + STRUT_PARTIAL_SET(self->strut, + data[0], data[2], data[1], data[3], + 0, 0, 0, 0, 0, 0, 0, 0); } - else - STRUT_SET(self->strut, 0, 0, 0, 0); - g_free(data); + g_free(data); } + if (!got) + STRUT_PARTIAL_SET(self->strut, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0); + /* updating here is pointless while we're being mapped cuz we're not in the client list yet */ if (self->frame) @@ -1658,11 +1736,18 @@ static void client_apply_startup_state(ObClient *self) */ } -void client_configure(ObClient *self, ObCorner anchor, - int x, int y, int w, int h, - gboolean user, gboolean final) +void client_configure_full(ObClient *self, ObCorner anchor, + int x, int y, int w, int h, + gboolean user, gboolean final, + gboolean force_reply) { gboolean moved = FALSE, resized = FALSE; + guint fdecor = self->frame->decorations; + + /* make the frame recalculate its dimentions n shit without changing + anything visible for real, this way the constraints below can work with + the updated frame dimensions. */ + frame_adjust_area(self->frame, TRUE, TRUE, TRUE); /* gets the frame's position */ frame_client_gravity(self->frame, &x, &y); @@ -1709,8 +1794,8 @@ void client_configure(ObClient *self, ObCorner anchor, /* set the size and position if maximized */ if (self->max_horz) { - x = a->x - self->frame->size.left; - w = a->width; + x = a->x; + w = a->width - self->frame->size.left - self->frame->size.right; } if (self->max_vert) { y = a->y; @@ -1789,11 +1874,13 @@ void client_configure(ObClient *self, ObCorner anchor, h /= self->size_inc.height; /* you cannot resize to nothing */ - if (w < 1) w = 1; - if (h < 1) h = 1; + if (basew + w < 1) w = 1 - basew; + if (baseh + h < 1) h = 1 - baseh; /* store the logical size */ - SIZE_SET(self->logical_size, w, h); + SIZE_SET(self->logical_size, + self->size_inc.width > 1 ? w : w + basew, + self->size_inc.height > 1 ? h : h + baseh); w *= self->size_inc.width; h *= self->size_inc.height; @@ -1839,34 +1926,32 @@ void client_configure(ObClient *self, ObCorner anchor, /* for app-requested resizes, always resize if 'resized' is true. for user-requested ones, only resize if final is true, or when - resizing in opaque mode */ + resizing in redraw mode */ if ((!user && resized) || - (user && (final || (resized && config_opaque_resize)))) + (user && (final || (resized && config_redraw_resize)))) XResizeWindow(ob_display, self->window, w, h); /* move/resize the frame to match the request */ if (self->frame) { - if (self->decorations != self->frame->decorations) + if (self->decorations != fdecor) moved = resized = TRUE; if (moved || resized) - frame_adjust_area(self->frame, moved, resized); + frame_adjust_area(self->frame, moved, resized, FALSE); - /* If you send this and the client hasn't changed you end up with buggy - clients (emacs) freaking out, cuz they send back a configure every - time they receive this event, which resends them this event... etc. - */ - if ((!user && moved) || (user && final)) { + if (!resized && (force_reply || ((!user && moved) || (user && final)))) + { XEvent event; event.type = ConfigureNotify; event.xconfigure.display = ob_display; event.xconfigure.event = self->window; event.xconfigure.window = self->window; - + /* root window real coords */ - event.xconfigure.x = self->frame->area.x + self->frame->size.left; - event.xconfigure.y = self->frame->area.y + self->frame->size.top; - + event.xconfigure.x = self->frame->area.x + self->frame->size.left - + self->border_width; + event.xconfigure.y = self->frame->area.y + self->frame->size.top - + self->border_width; event.xconfigure.width = w; event.xconfigure.height = h; event.xconfigure.border_width = 0; @@ -2122,7 +2207,7 @@ void client_shade(ObClient *self, gboolean shade) self->shaded = shade; client_change_state(self); /* resize the frame to just the titlebar */ - frame_adjust_area(self->frame, FALSE, FALSE); + frame_adjust_area(self->frame, FALSE, FALSE, FALSE); } void client_close(ObClient *self) @@ -2476,16 +2561,19 @@ void client_unfocus(ObClient *self) focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING); } -void client_activate(ObClient *self) +void client_activate(ObClient *self, gboolean here) { if (client_normal(self) && screen_showing_desktop) screen_show_desktop(FALSE); if (self->iconic) client_iconify(self, FALSE, FALSE); if (self->desktop != DESKTOP_ALL && - self->desktop != screen_desktop) - screen_set_desktop(self->desktop); - else if (!self->frame->visible) + self->desktop != screen_desktop) { + if (here) + client_set_desktop(self, screen_desktop, FALSE); + else + screen_set_desktop(self->desktop); + } else if (!self->frame->visible) /* if its not visible for other reasons, then don't mess with it */ return; @@ -2568,7 +2656,8 @@ ObClient *client_find_directional(ObClient *c, ObDirection dir) his_cy = (cur->frame->area.y - my_cy) + cur->frame->area.height / 2; - if(dir > 3) { + if(dir == OB_DIRECTION_NORTHEAST || dir == OB_DIRECTION_SOUTHEAST || + dir == OB_DIRECTION_SOUTHWEST || dir == OB_DIRECTION_NORTHWEST) { int tx; /* Rotate the diagonals 45 degrees counterclockwise. * To do this, multiply the matrix /+h +h\ with the @@ -2687,3 +2776,203 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) } return NULL; } + +gchar* client_get_sm_client_id(ObClient *self) +{ + gchar *id = NULL; + + if (!PROP_GETS(self->window, sm_client_id, locale, &id) && self->group) + PROP_GETS(self->group->leader, sm_client_id, locale, &id); + return id; +} + +/* 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. + */ +int client_directional_edge_search(ObClient *c, ObDirection dir) +{ + int dest; + int my_edge_start, my_edge_end, my_offset; + GList *it; + Rect *a; + + if(!client_list) + return -1; + + a = screen_area(c->desktop); + + switch(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; + + dest = a->y; /* default: top of screen */ + + for(it = g_list_first(client_list); it; it = it->next) { + int his_edge_start, his_edge_end, his_offset; + ObClient *cur = it->data; + + if(cur == c) + continue; + if(!client_normal(cur)) + continue; + if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL) + continue; + if(cur->iconic) + continue; + + 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; + + 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; + + } + 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; + + dest = a->y + a->height; /* default: bottom of screen */ + + for(it = g_list_first(client_list); it; it = it->next) { + int his_edge_start, his_edge_end, his_offset; + ObClient *cur = it->data; + + if(cur == c) + continue; + if(!client_normal(cur)) + continue; + if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL) + continue; + if(cur->iconic) + continue; + + his_edge_start = cur->frame->area.x; + his_edge_end = cur->frame->area.x + cur->frame->area.width; + his_offset = cur->frame->area.y; + + + 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; + + } + 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; + + dest = a->x; /* default: leftmost egde of screen */ + + for(it = g_list_first(client_list); it; it = it->next) { + int his_edge_start, his_edge_end, his_offset; + ObClient *cur = it->data; + + if(cur == c) + continue; + if(!client_normal(cur)) + continue; + if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL) + continue; + if(cur->iconic) + continue; + + 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; + + 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; + + + } + 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; + + dest = a->x + a->width; /* default: rightmost edge of screen */ + + for(it = g_list_first(client_list); it; it = it->next) { + int his_edge_start, his_edge_end, his_offset; + ObClient *cur = it->data; + + if(cur == c) + continue; + if(!client_normal(cur)) + continue; + if(c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL) + continue; + if(cur->iconic) + continue; + + his_edge_start = cur->frame->area.y; + his_edge_end = cur->frame->area.y + cur->frame->area.height; + his_offset = cur->frame->area.x; + + 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; + + } + break; + case OB_DIRECTION_NORTHEAST: + case OB_DIRECTION_SOUTHEAST: + case OB_DIRECTION_NORTHWEST: + case OB_DIRECTION_SOUTHWEST: + /* not implemented */ + break; + default: + g_assert_not_reached(); + } + return dest; +}