/* -*-c-*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* ---------------------------- included header files ---------------------- */ #include "config.h" #include #include #include "libs/fvwmlib.h" #include "libs/FShape.h" #include "libs/Grab.h" #include "libs/charmap.h" #include "libs/wcontext.h" #include "fvwm.h" #include "externs.h" #include "execcontext.h" #include "events.h" #include "misc.h" #include "screen.h" #include "geometry.h" #include "module_interface.h" #include "focus.h" #include "borders.h" #include "frame.h" #include "gnome.h" #include "ewmh.h" /* ---------------------------- local definitions -------------------------- */ /* ---------------------------- local macros ------------------------------- */ /* ---------------------------- imports ------------------------------------ */ /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ typedef struct { int decor_grav; int title_grav; int lbutton_grav; int rbutton_grav; int parent_grav; int client_grav; } frame_decor_gravities_type; typedef struct { /* filled when args are created */ frame_move_resize_mode mode; frame_decor_gravities_type grav; size_borders b_g; size_borders b_no_title_g; rectangle curr_sidebar_g; rectangle start_g; rectangle end_g; rectangle delta_g; rectangle current_g; rectangle client_g; int anim_steps; Window w_with_focus; int current_step; int curr_titlebar_compression; direction_t shade_dir; window_parts trans_parts; struct { unsigned do_force : 1; unsigned do_not_configure_client : 1; unsigned do_not_draw : 1; unsigned do_restore_gravity : 1; unsigned do_set_bit_gravity : 1; unsigned do_update_shape : 1; unsigned had_handles : 1; unsigned is_lazy_shading : 1; unsigned is_setup : 1; unsigned is_shading : 1; unsigned was_moved : 1; } flags; /* used during the animation */ int next_titlebar_compression; rectangle next_sidebar_g; rectangle next_g; rectangle dstep_g; size_rect parent_s; int minimal_w_offset; int minimal_h_offset; struct { /* cleared before each step */ unsigned do_hide_parent : 1; unsigned do_unhide_parent : 1; unsigned is_hidden : 1; unsigned was_hidden : 1; } step_flags; } mr_args_internal; /* ---------------------------- forward declarations ----------------------- */ /* ---------------------------- local variables ---------------------------- */ /* windows used to hide animation steps */ static struct { Window parent; Window w[4]; } hide_wins; /* ---------------------------- exported variables (globals) --------------- */ /* ---------------------------- local functions ---------------------------- */ #if 0 static void print_g(char *text, rectangle *g) { if (g == NULL) { fprintf(stderr, "%s: (null)", (text == NULL) ? "" : text); } else { fprintf(stderr, "%s: %4d %4d %4dx%4d (%4d - %4d %4d - %4d)\n", (text == NULL) ? "" : text, g->x, g->y, g->width, g->height, g->x, g->x + g->width - 1, g->y, g->y + g->height - 1); } } #endif static void combine_gravities( frame_decor_gravities_type *ret_grav, frame_decor_gravities_type *grav_x, frame_decor_gravities_type *grav_y) { ret_grav->decor_grav = gravity_combine_xy_grav( grav_x->decor_grav, grav_y->decor_grav); ret_grav->title_grav = gravity_combine_xy_grav( grav_x->title_grav, grav_y->title_grav); ret_grav->lbutton_grav = gravity_combine_xy_grav( grav_x->lbutton_grav, grav_y->lbutton_grav); ret_grav->rbutton_grav = gravity_combine_xy_grav( grav_x->rbutton_grav, grav_y->rbutton_grav); ret_grav->parent_grav = gravity_combine_xy_grav( grav_x->parent_grav, grav_y->parent_grav); ret_grav->client_grav = gravity_combine_xy_grav( grav_x->client_grav, grav_y->client_grav); return; } static void get_resize_decor_gravities_one_axis( frame_decor_gravities_type *ret_grav, direction_t title_dir, frame_move_resize_mode axis_mode, direction_t neg_dir, direction_t pos_dir, int is_moving) { int title_grav; int neg_grav; int pos_grav; title_grav = gravity_dir_to_grav(title_dir); neg_grav = gravity_dir_to_grav(neg_dir); pos_grav = gravity_dir_to_grav(pos_dir); if (title_dir != DIR_NONE) { ret_grav->decor_grav = title_grav; ret_grav->lbutton_grav = title_grav; ret_grav->title_grav = title_grav; ret_grav->rbutton_grav = title_grav; } else { ret_grav->decor_grav = neg_grav; ret_grav->lbutton_grav = neg_grav; ret_grav->title_grav = neg_grav; ret_grav->rbutton_grav = pos_grav; } switch (axis_mode) { case FRAME_MR_SCROLL: ret_grav->client_grav = (is_moving) ? neg_grav : pos_grav; break; case FRAME_MR_SHRINK: ret_grav->client_grav = (is_moving) ? pos_grav : neg_grav; break; case FRAME_MR_OPAQUE: case FRAME_MR_FORCE_SETUP: case FRAME_MR_FORCE_SETUP_NO_W: case FRAME_MR_SETUP: case FRAME_MR_SETUP_BY_APP: ret_grav->client_grav = neg_grav; break; case FRAME_MR_DONT_DRAW: /* can not happen, just a dummy to keep -Wall happy */ break; } ret_grav->parent_grav = ret_grav->client_grav; return; } static void frame_get_titlebar_dimensions_only( FvwmWindow *fw, rectangle *frame_g, size_borders *bs, rectangle *ret_titlebar_g) { if (!HAS_TITLE(fw)) { return; } switch (GET_TITLE_DIR(fw)) { case DIR_W: case DIR_E: ret_titlebar_g->x = (GET_TITLE_DIR(fw) == DIR_W) ? bs->top_left.width : frame_g->width - bs->bottom_right.width - fw->title_thickness; ret_titlebar_g->y = bs->top_left.height; ret_titlebar_g->width = fw->title_thickness; ret_titlebar_g->height = frame_g->height - bs->total_size.height; break; case DIR_N: case DIR_S: default: /* default makes gcc4 happy */ ret_titlebar_g->y = (GET_TITLE_DIR(fw) == DIR_N) ? bs->top_left.height : frame_g->height - bs->bottom_right.height - fw->title_thickness; ret_titlebar_g->x = bs->top_left.width; ret_titlebar_g->width = frame_g->width - bs->total_size.width; ret_titlebar_g->height = fw->title_thickness; break; } return; } static void frame_setup_border( FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts, rectangle *diff_g) { XWindowChanges xwc; Window w; window_parts part; rectangle sidebar_g; rectangle part_g; Bool dummy; if (HAS_NO_BORDER(fw)) { return; } frame_get_sidebar_geometry( fw, NULL, frame_g, &sidebar_g, &dummy, &dummy); for (part = PART_BORDER_N; (part & PART_FRAME); part <<= 1) { if ((part & PART_FRAME & setup_parts) == PART_NONE) { continue; } border_get_part_geometry(fw, part, &sidebar_g, &part_g, &w); if (part_g.width <= 0 || part_g.height <= 0) { xwc.x = -1; xwc.y = -1; xwc.width = 1; xwc.height = 1; } else { xwc.x = part_g.x; xwc.y = part_g.y; xwc.width = part_g.width; xwc.height = part_g.height; } if (diff_g != NULL) { if (part == PART_BORDER_NE || part == PART_BORDER_E || part == PART_BORDER_SE) { xwc.x -= diff_g->width; } if (part == PART_BORDER_SW || part == PART_BORDER_S || part == PART_BORDER_SE) { xwc.y -= diff_g->height; } } XConfigureWindow(dpy, w, CWWidth | CWHeight | CWX | CWY, &xwc); } return; } static void frame_setup_titlebar( FvwmWindow *fw, rectangle *frame_g, window_parts setup_parts, rectangle *diff_g) { frame_title_layout_t title_layout; int i; if (!HAS_TITLE(fw)) { return; } frame_get_titlebar_dimensions(fw, frame_g, diff_g, &title_layout); /* configure buttons */ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (FW_W_BUTTON(fw, i) != None && (setup_parts & PART_BUTTONS)) { XMoveResizeWindow( dpy, FW_W_BUTTON(fw, i), title_layout.button_g[i].x, title_layout.button_g[i].y, title_layout.button_g[i].width, title_layout.button_g[i].height); } } /* configure title */ if (setup_parts & PART_TITLE) { XMoveResizeWindow( dpy, FW_W_TITLE(fw), title_layout.title_g.x, title_layout.title_g.y, title_layout.title_g.width, title_layout.title_g.height); } return; } static void __frame_setup_window( FvwmWindow *fw, rectangle *frame_g, Bool do_send_configure_notify, Bool do_force, Bool is_application_request) { frame_move_resize_args mr_args; Bool is_resized = False; Bool is_moved = False; rectangle new_g; new_g = *frame_g; /* sanity checks */ if (new_g.width < 1) { new_g.width = 1; } if (new_g.height < 1) { new_g.height = 1; } /* set some flags */ if (new_g.width != fw->g.frame.width || new_g.height != fw->g.frame.height) { is_resized = True; } if (new_g.x != fw->g.frame.x || new_g.y != fw->g.frame.y) { is_moved = True; } /* setup the window */ if (is_resized || do_force) { frame_move_resize_mode mode; if (is_application_request) { mode = FRAME_MR_SETUP_BY_APP; } else if (do_force) { mode = FRAME_MR_FORCE_SETUP; } else { mode = FRAME_MR_SETUP; } mr_args = frame_create_move_resize_args( fw, mode, NULL, &new_g, 0, DIR_NONE); frame_move_resize(fw, mr_args); ((mr_args_internal *)mr_args)->flags.was_moved = 0; frame_free_move_resize_args(fw, mr_args); fw->g.frame = *frame_g; } else if (is_moved) { unsigned int draw_parts = PART_NONE; /* inform the application of the change * * According to the July 27, 1988 ICCCM draft, we should send a * synthetic ConfigureNotify event to the client if the window * was moved but not resized. */ XMoveWindow(dpy, FW_W_FRAME(fw), frame_g->x, frame_g->y); fw->g.frame = *frame_g; if ((draw_parts = border_get_transparent_decorations_part(fw)) != PART_NONE) { border_draw_decorations( fw, draw_parts, ((fw == get_focus_window())) ? True : False, True, CLEAR_ALL, NULL, NULL); } fw->g.frame = *frame_g; do_send_configure_notify = True; } /* must not send events to shaded windows because this might cause them * to look at their current geometry */ if (do_send_configure_notify && !IS_SHADED(fw)) { SendConfigureNotify( fw, new_g.x, new_g.y, new_g.width, new_g.height, 0, True); } /* get things updated */ XFlush(dpy); /* inform the modules of the change */ BroadcastConfig(M_CONFIGURE_WINDOW,fw); return; } static void frame_reparent_hide_windows( Window w) { int i; hide_wins.parent = w; for (i = 0; i < 4 ; i++) { if (w == Scr.Root) { XUnmapWindow(dpy, hide_wins.w[i]); } XReparentWindow(dpy, hide_wins.w[i], w, -1, -1); } if (w != Scr.Root) { XRaiseWindow(dpy, hide_wins.w[0]); XRestackWindows(dpy, hide_wins.w, 4); } return; } /* Returns True if the frame is so small that the parent window would have a * width or height smaller than one pixel. */ static Bool frame_is_parent_hidden( FvwmWindow *fw, rectangle *frame_g) { size_borders b; get_window_borders(fw, &b); if (frame_g->width <= b.total_size.width || frame_g->height <= b.total_size.height) { return True; } return False; } /* Returns the number of pixels that the title bar is too short to accomodate * all the title buttons and a title window that has at least a length of one * pixel. */ static int frame_get_titlebar_compression( FvwmWindow *fw, rectangle *frame_g) { size_borders b; int space; int need_space; if (!HAS_TITLE(fw)) { return 0; } get_window_borders(fw, &b); if (HAS_VERTICAL_TITLE(fw)) { space = frame_g->height - b.total_size.height; } else { space = frame_g->width - b.total_size.width; } need_space = (fw->nr_left_buttons + fw->nr_right_buttons) * fw->title_thickness + MIN_WINDOW_TITLE_LENGTH; if (space < need_space) { return need_space - space; } return 0; } /* Calculates the gravities for the various parts of the decor through ret_grav. * This can be passed to frame_set_decor_gravities. * * title_dir * The direction of the title in the frame. * rmode * The mode for the resize operation */ static void frame_get_resize_decor_gravities( frame_decor_gravities_type *ret_grav, direction_t title_dir, frame_move_resize_mode rmode, rectangle *delta_g) { frame_decor_gravities_type grav_x; frame_decor_gravities_type grav_y; direction_t title_dir_x; direction_t title_dir_y; gravity_split_xy_dir(&title_dir_x, &title_dir_y, title_dir); get_resize_decor_gravities_one_axis( &grav_x, title_dir_x, rmode, DIR_W, DIR_E, (delta_g->x != 0)); get_resize_decor_gravities_one_axis( &grav_y, title_dir_y, rmode, DIR_N, DIR_S, (delta_g->y != 0)); combine_gravities(ret_grav, &grav_x, &grav_y); return; } /* sets the gravity for the various parts of the window */ static void frame_set_decor_gravities( FvwmWindow *fw, frame_decor_gravities_type *grav, int do_set1_restore2_bit_gravity) { int valuemask; XSetWindowAttributes xcwa; int i; Bool button_reverted = False; /* using bit gravity can reduce redrawing dramatically */ valuemask = CWWinGravity; xcwa.win_gravity = grav->client_grav; if (do_set1_restore2_bit_gravity == 1) { XWindowAttributes xwa; if (!fw->attr_backup.is_bit_gravity_stored && XGetWindowAttributes(dpy, FW_W(fw), &xwa)) { fw->attr_backup.bit_gravity = xwa.bit_gravity; } fw->attr_backup.is_bit_gravity_stored = 1; valuemask |= CWBitGravity; xcwa.bit_gravity = grav->client_grav; } else if (do_set1_restore2_bit_gravity == 2) { fw->attr_backup.is_bit_gravity_stored = 0; valuemask |= CWBitGravity; xcwa.bit_gravity = fw->attr_backup.bit_gravity; } XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa); xcwa.win_gravity = grav->parent_grav; valuemask = CWWinGravity; XChangeWindowAttributes(dpy, FW_W_PARENT(fw), valuemask, &xcwa); if (!HAS_TITLE(fw)) { return; } xcwa.win_gravity = grav->title_grav; XChangeWindowAttributes(dpy, FW_W_TITLE(fw), valuemask, &xcwa); if (fw->title_text_rotation == ROTATION_270 || fw->title_text_rotation == ROTATION_180) { button_reverted = True; } if (button_reverted) { xcwa.win_gravity = grav->rbutton_grav; } else { xcwa.win_gravity = grav->lbutton_grav; } for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i += 2) { if (FW_W_BUTTON(fw, i)) { XChangeWindowAttributes( dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa); } } if (button_reverted) { xcwa.win_gravity = grav->lbutton_grav; } else { xcwa.win_gravity = grav->rbutton_grav; } for (i = 1; i < NUMBER_OF_TITLE_BUTTONS; i += 2) { if (FW_W_BUTTON(fw, i)) { XChangeWindowAttributes( dpy, FW_W_BUTTON(fw, i), valuemask, &xcwa); } } return; } /* Just restore the win and bit gravities on the client window. */ static void frame_restore_client_gravities(FvwmWindow *fw) { XSetWindowAttributes xcwa; long valuemask; valuemask = CWWinGravity; if (fw->attr_backup.is_bit_gravity_stored) { fw->attr_backup.is_bit_gravity_stored = 0; xcwa.bit_gravity = fw->attr_backup.bit_gravity; valuemask |= CWBitGravity; } xcwa.win_gravity = fw->hints.win_gravity; XChangeWindowAttributes(dpy, FW_W(fw), valuemask, &xcwa); return; } /* Prepares the structure for the next animation step. */ static void frame_next_move_resize_args( frame_move_resize_args mr_args) { mr_args_internal *mra; mra = (mr_args_internal *)mr_args; mra->curr_sidebar_g = mra->next_sidebar_g; mra->current_g = mra->next_g; mra->step_flags.was_hidden = mra->step_flags.is_hidden; mra->curr_titlebar_compression = mra->next_titlebar_compression; return; } static rectangle *frame_get_hidden_pos( FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide, rectangle *ret_hidden_g) { rectangle *target_g; direction_t dir_x; direction_t dir_y; if (do_unhide == False) { gravity_split_xy_dir(&dir_x, &dir_y, mra->shade_dir); ret_hidden_g->x = (dir_x == DIR_E) ? -mra->client_g.width + mra->parent_s.width : 0; ret_hidden_g->y = (dir_y == DIR_S) ? -mra->client_g.height + mra->parent_s.height : 0; target_g = &mra->next_g; } else { gravity_split_xy_dir(&dir_x, &dir_y, SHADED_DIR(fw)); if (mra->mode == FRAME_MR_SCROLL) { ret_hidden_g->x = (dir_x == DIR_W) ? -mra->client_g.width + mra->parent_s.width : 0; ret_hidden_g->y = (dir_y == DIR_N) ? -mra->client_g.height + mra->parent_s.height : 0; } else { ret_hidden_g->x = (dir_x == DIR_E) ? -mra->client_g.width + mra->parent_s.width : 0; ret_hidden_g->y = (dir_y == DIR_S) ? -mra->client_g.height + mra->parent_s.height : 0; } target_g = &mra->next_g; } return target_g; } static void frame_update_hidden_window_pos( FvwmWindow *fw, mr_args_internal *mra, Bool do_unhide) { rectangle *target_g; rectangle hidden_g; target_g = frame_get_hidden_pos(fw, mra, do_unhide, &hidden_g); XMoveResizeWindow( dpy, FW_W_PARENT(fw), mra->b_g.top_left.width, mra->b_g.top_left.height, max(1, target_g->width - mra->b_g.total_size.width), max(1, target_g->height - mra->b_g.total_size.height)); XMoveResizeWindow( dpy, FW_W(fw), hidden_g.x, hidden_g.y, mra->client_g.width, mra->client_g.height); mra->flags.was_moved = 1; return; } static void frame_prepare_animation_shape( FvwmWindow *fw, mr_args_internal *mra, int parent_x, int parent_y) { rectangle parent_g; rectangle client_g; if (!FShapesSupported) { return; } parent_g.x = parent_x; parent_g.y = parent_y; parent_g.width = mra->parent_s.width; parent_g.height = mra->parent_s.height; gravity_move_resize_parent_child( mra->grav.parent_grav, &mra->dstep_g, &parent_g); client_g = mra->client_g; frame_get_hidden_pos(fw, mra, True, &client_g); client_g.x += parent_g.x; client_g.y += parent_g.y; FShapeCombineShape( dpy, Scr.NoFocusWin, FShapeBounding, client_g.x, client_g.y, FW_W(fw), FShapeBounding, FShapeSet); if (HAS_TITLE(fw)) { rectangle tb_g; XRectangle rect; frame_get_titlebar_dimensions_only( fw, &mra->next_g, &mra->b_no_title_g, &tb_g); /* windows w/ titles */ rect.x = tb_g.x; rect.y = tb_g.y; rect.width = tb_g.width; rect.height = tb_g.height; FShapeCombineRectangles( dpy, Scr.NoFocusWin, FShapeBounding, 0, 0, &rect, 1, FShapeUnion, Unsorted); } return; } static void frame_mrs_prepare_vars( FvwmWindow *fw, mr_args_internal *mra) { Bool dummy; int i; /* preparations */ i = mra->current_step; mra->next_g = mra->start_g; mra->next_g.x += (mra->delta_g.x * i) / mra->anim_steps; mra->next_g.y += (mra->delta_g.y * i) / mra->anim_steps; mra->next_g.width += (mra->delta_g.width * i) / mra->anim_steps; mra->next_g.height += (mra->delta_g.height * i) / mra->anim_steps; frame_get_sidebar_geometry( fw, NULL, &mra->next_g, &mra->next_sidebar_g, &dummy, &dummy); fvwmrect_subtract_rectangles( &mra->dstep_g, &mra->next_g, &mra->current_g); mra->next_titlebar_compression = frame_get_titlebar_compression(fw, &mra->next_g); mra->step_flags.is_hidden = (frame_is_parent_hidden(fw, &mra->next_g) == True); mra->step_flags.do_hide_parent = ((!mra->step_flags.was_hidden || mra->flags.do_force) && mra->step_flags.is_hidden); mra->step_flags.do_unhide_parent = ((mra->step_flags.was_hidden || mra->flags.do_force) && !mra->step_flags.is_hidden); /* get the parent's dimensions */ mra->parent_s.width = mra->next_g.width - mra->b_g.total_size.width; if (mra->parent_s.width < 1) { mra->minimal_w_offset = 1 - mra->parent_s.width; mra->parent_s.width = 1; } else { mra->minimal_w_offset = 0; } mra->parent_s.height = mra->next_g.height - mra->b_g.total_size.height; if (mra->parent_s.height < 1) { mra->minimal_h_offset = 1 - mra->parent_s.height; mra->parent_s.height = 1; } else { mra->minimal_h_offset = 0; } return; } static void frame_mrs_hide_changing_parts( mr_args_internal *mra) { int l_add; int t_add; int r_add; int b_add; int w; int h; t_add = 0; l_add = 0; b_add = 0; r_add = 0; if (mra->mode == FRAME_MR_SHRINK) { if (mra->dstep_g.x > 0) { l_add = mra->dstep_g.x; } if (mra->dstep_g.y > 0) { t_add = mra->dstep_g.y; } } else if (mra->mode == FRAME_MR_SCROLL) { if (mra->dstep_g.x == 0 && mra->dstep_g.width < 0) { l_add = -mra->dstep_g.width; } if (mra->dstep_g.y == 0 && mra->dstep_g.height < 0) { t_add = -mra->dstep_g.height; } } if (l_add > 0) { l_add -= mra->minimal_w_offset; } else { r_add = (mra->dstep_g.width < 0) ? -mra->dstep_g.width : 0; r_add -= mra->minimal_w_offset; } if (t_add > 0) { t_add -= mra->minimal_h_offset; } else { b_add = (mra->dstep_g.height < 0) ? -mra->dstep_g.height : 0; b_add -= mra->minimal_h_offset; } /* cover top border */ w = mra->current_g.width; h = mra->b_g.top_left.height + t_add; if (w > 0 && h > 0) { XMoveResizeWindow(dpy, hide_wins.w[0], 0, 0, w, h); XMapWindow(dpy, hide_wins.w[0]); } /* cover left border */ w = mra->b_g.top_left.width + l_add; h = mra->current_g.height; if (w > 0 && h > 0) { XMoveResizeWindow(dpy, hide_wins.w[1], 0, 0, w, h); XMapWindow(dpy, hide_wins.w[1]); } /* cover bottom border and possibly part of the client */ w = mra->current_g.width; h = mra->b_g.bottom_right.height + b_add; if (w > 0 && h > 0) { XMoveResizeWindow( dpy, hide_wins.w[2], 0, mra->current_g.height - mra->b_g.bottom_right.height - b_add, w, h); XMapWindow(dpy, hide_wins.w[2]); } /* cover right border and possibly part of the client */ w = mra->b_g.bottom_right.width + r_add; h = mra->current_g.height; if (w > 0 && h > 0) { XMoveResizeWindow( dpy, hide_wins.w[3], mra->current_g.width - mra->b_g.bottom_right.width - r_add, 0, w, h); XMapWindow(dpy, hide_wins.w[3]); } return; } static void frame_mrs_hide_unhide_parent( FvwmWindow *fw, mr_args_internal *mra) { XSetWindowAttributes xswa; if (mra->step_flags.do_unhide_parent) { Window w[2]; /* update the hidden position of the client */ frame_update_hidden_window_pos(fw, mra, True); w[0] = hide_wins.w[3]; w[1] = FW_W_PARENT(fw); XRestackWindows(dpy, w, 2); } else if (mra->step_flags.do_hide_parent) { /* When the parent gets hidden, unmap it automatically, lower * it while hidden, then remap it. Necessary to eliminate * flickering. */ xswa.win_gravity = UnmapGravity; XChangeWindowAttributes( dpy, FW_W_PARENT(fw), CWWinGravity, &xswa); } return; } static void frame_mrs_hide_unhide_parent2( FvwmWindow *fw, mr_args_internal *mra) { XSetWindowAttributes xswa; /* finish hiding the parent */ if (mra->step_flags.do_hide_parent) { xswa.win_gravity = mra->grav.parent_grav; XChangeWindowAttributes( dpy, FW_W_PARENT(fw), CWWinGravity, &xswa); /* update the hidden position of the client */ frame_update_hidden_window_pos(fw, mra, False); XLowerWindow(dpy, FW_W_PARENT(fw)); XMapWindow(dpy, FW_W_PARENT(fw)); } return; } static void frame_mrs_setup_draw_decorations( FvwmWindow *fw, mr_args_internal *mra) { window_parts setup_parts; /* setup the title bar and the border */ setup_parts = PART_TITLE; if (mra->curr_titlebar_compression != mra->next_titlebar_compression || mra->mode == FRAME_MR_FORCE_SETUP) { setup_parts |= PART_BUTTONS; } frame_setup_titlebar(fw, &mra->next_g, setup_parts, &mra->dstep_g); frame_setup_border(fw, &mra->next_g, PART_ALL, &mra->dstep_g); /* draw the border and the titlebar */ if (mra->flags.do_not_draw == 1) { /* nothing */ } else if (!mra->flags.is_shading || !mra->flags.is_lazy_shading) { /* draw as usual */ border_draw_decorations( fw, PART_ALL, (mra->w_with_focus != None) ? True : False, (mra->flags.do_force) ? True : False, CLEAR_ALL, &mra->current_g, &mra->next_g); } else /* lazy shading */ { /* Lazy shading relies on the proper window gravities and does * not redraw the decorations during the animation. Only draw * on the first step. */ if (mra->current_step == 1) { rectangle lazy_g; /* Use the larger width and height values from the * current and the final geometry to get proper * decorations. */ lazy_g.x = mra->current_g.x; lazy_g.y = mra->current_g.y; lazy_g.width = max( mra->current_g.width, mra->end_g.width); lazy_g.height = max( mra->current_g.height, mra->end_g.height); border_draw_decorations( fw, PART_ALL, (mra->w_with_focus != None) ? True : False, True, CLEAR_ALL, &mra->current_g, &lazy_g); } } return; } static void frame_mrs_resize_move_windows( FvwmWindow *fw, mr_args_internal *mra) { /* setup the parent, the frame and the client window */ if (!mra->flags.is_shading) { if (!mra->step_flags.is_hidden && !mra->flags.do_not_configure_client) { XMoveResizeWindow( dpy, FW_W(fw), 0, 0, mra->parent_s.width, mra->parent_s.height); mra->client_g.width = mra->parent_s.width; mra->client_g.height = mra->parent_s.height; } else { XMoveWindow(dpy, FW_W(fw), 0, 0); } mra->flags.was_moved = 1; #if 0 /* reduces flickering */ /* dv (11-Aug-2002): ... and slows down large scripts * dramatically. Rather let it flicker */ if (mra->flags.is_setup) { usleep(1000); } #endif XSync(dpy, 0); XMoveResizeWindow( dpy, FW_W_PARENT(fw), mra->b_g.top_left.width, mra->b_g.top_left.height, mra->parent_s.width, mra->parent_s.height); } else { int x; int y; x = mra->b_g.top_left.width; y = mra->b_g.top_left.height; if (mra->mode == FRAME_MR_SCROLL) { if (mra->dstep_g.x == 0) { x -= mra->dstep_g.width - mra->minimal_w_offset; } if (mra->dstep_g.y == 0) { y -= mra->dstep_g.height - mra->minimal_h_offset;; } } else if (mra->mode == FRAME_MR_SHRINK) { x += mra->dstep_g.x; y += mra->dstep_g.y; } if (x > 0) { x -= mra->minimal_w_offset; } else if (x < 0) { x += mra->minimal_w_offset; } if (y > 0) { y -= mra->minimal_h_offset; } else if (y < 0) { y += mra->minimal_h_offset; } XMoveResizeWindow( dpy, FW_W_PARENT(fw), x, y, mra->parent_s.width, mra->parent_s.height); if (mra->flags.do_update_shape) { /* Step 1: apply the union of the old and new shapes. * This way so that the client stays visible - rather * let the background show through than force an * Expose event. */ frame_prepare_animation_shape(fw, mra, x, y); FShapeCombineShape( dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, Scr.NoFocusWin, FShapeBounding, FShapeUnion); } } XMoveResizeWindow( dpy, FW_W_FRAME(fw), mra->next_g.x, mra->next_g.y, mra->next_g.width, mra->next_g.height); if (mra->flags.do_update_shape) { /* Step 2: clip the previous shape. */ FShapeCombineShape( dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, Scr.NoFocusWin, FShapeBounding, FShapeSet); } return; } static void frame_move_resize_step( FvwmWindow *fw, mr_args_internal *mra) { frame_mrs_prepare_vars(fw, mra); frame_mrs_hide_changing_parts(mra); frame_mrs_hide_unhide_parent(fw, mra); frame_mrs_setup_draw_decorations(fw, mra); frame_mrs_resize_move_windows(fw, mra); frame_mrs_hide_unhide_parent2(fw, mra); fw->g.frame = mra->next_g; return; } static void frame_has_handles_and_tiled_border( FvwmWindow *fw, int *ret_has_handles, int *ret_has_tiled_border) { DecorFace *df; *ret_has_handles = 1; if (!HAS_HANDLES(fw)) { *ret_has_handles = 0; } df = border_get_border_style(fw, (fw == Scr.Hilite) ? True : False); if (DFS_HAS_HIDDEN_HANDLES(df->style)) { *ret_has_handles = 0; } *ret_has_tiled_border = (DFS_FACE_TYPE(df->style) == TiledPixmapButton) || (DFS_FACE_TYPE(df->style) == ColorsetButton && !CSET_IS_TRANSPARENT_PR(df->u.acs.cs) && CSET_HAS_PIXMAP(df->u.acs.cs)); return; } static int frame_get_shading_laziness( FvwmWindow *fw, mr_args_internal *mra) { int has_handles; int has_tiled_pixmap_border; int using_border_style; if (!mra->flags.is_shading || mra->anim_steps <= 2) { return 0; } frame_has_handles_and_tiled_border( fw, &has_handles, &has_tiled_pixmap_border); if (HAS_TITLE(fw) && has_tiled_pixmap_border) { using_border_style = border_is_using_border_style( fw, (fw == Scr.Hilite) ? True : False); } else { using_border_style = 0; } switch (WINDOWSHADE_LAZINESS(fw)) { case WINDOWSHADE_ALWAYS_LAZY: return 1; case WINDOWSHADE_BUSY: if (has_handles) { return 0; } /* fall through */ case WINDOWSHADE_LAZY: default: if (has_tiled_pixmap_border && !HAS_NO_BORDER(fw)) { return 0; } else if (has_tiled_pixmap_border && HAS_TITLE(fw) && using_border_style) { return 0; } return 1; } } void frame_reshape_border(FvwmWindow *fw) { int grav; int off_x = 0; int off_y = 0; rectangle naked_g; rectangle *new_g; /* calculate the new offsets */ if (!IS_MAXIMIZED(fw)) { grav = fw->hints.win_gravity; new_g = &fw->g.normal; } else { /* maximized windows are always considered to have * NorthWestGravity */ grav = NorthWestGravity; new_g = &fw->g.max; off_x = fw->g.normal.x - fw->g.max.x; off_y = fw->g.normal.y - fw->g.max.y; } gravity_get_naked_geometry(grav, fw, &naked_g, new_g); gravity_translate_to_northwest_geometry_no_bw( grav, fw, &naked_g, &naked_g); set_window_border_size(fw, fw->unshaped_boundary_width); gravity_add_decoration(grav, fw, new_g, &naked_g); if (IS_MAXIMIZED(fw)) { /* prevent random paging when unmaximizing after the border * width has changed */ fw->g.max_offset.x += fw->g.normal.x - fw->g.max.x - off_x; fw->g.max_offset.y += fw->g.normal.y - fw->g.max.y - off_y; } if (IS_SHADED(fw)) { get_unshaded_geometry(fw, new_g); if (USED_TITLE_DIR_FOR_SHADING(fw)) { SET_SHADED_DIR(fw, GET_TITLE_DIR(fw)); } get_shaded_geometry(fw, &fw->g.frame, new_g); frame_force_setup_window( fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width, fw->g.frame.height, False); } else { get_relative_geometry(new_g, new_g); frame_force_setup_window( fw, new_g->x, new_g->y, new_g->width, new_g->height, True); } return; } /* ---------------------------- interface functions ------------------------ */ /* Initialise structures local to frame.c */ void frame_init(void) { XSetWindowAttributes xswa; unsigned long valuemask; int i; xswa.override_redirect = True; xswa.backing_store = NotUseful; xswa.save_under = False; xswa.win_gravity = UnmapGravity; xswa.background_pixmap = None; valuemask = CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWBackPixmap | CWWinGravity; hide_wins.parent = Scr.Root; for (i = 0; i < 4; i++) { hide_wins.w[i] = XCreateWindow( dpy, Scr.Root, -1, -1, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, valuemask, &xswa); if (hide_wins.w[i] == None) { fvwm_msg(ERR, "frame_init", "Could not create internal windows. Exiting"); MyXUngrabServer(dpy); exit(1); } } return; } Bool is_frame_hide_window( Window w) { int i; if (w == None) { return False; } for (i = 0; i < 4; i++) { if (w == hide_wins.w[i]) { return True; } } return False; } void frame_destroyed_frame( Window frame_w) { if (hide_wins.parent == frame_w) { /* Oops, the window containing the hide windows was destroyed! * Let it die and create them from scratch. */ frame_init(); } return; } void frame_get_titlebar_dimensions( FvwmWindow *fw, rectangle *frame_g, rectangle *diff_g, frame_title_layout_t *title_layout) { size_borders b; int i; int tb_length; int tb_thick; int tb_x; int tb_y; int tb_w; int tb_h; int b_length; int b_w; int b_h; int t_length; int t_w; int t_h; int br_sub; int nbuttons; int nbuttons_big; int *padd_coord; int *b_l; Bool revert_button = False; if (!HAS_TITLE(fw)) { return; } get_window_borders_no_title(fw, &b); if (HAS_VERTICAL_TITLE(fw)) { tb_length = frame_g->height - b.total_size.height; } else { tb_length = frame_g->width - b.total_size.width; } /* find out the length of the title and the buttons */ tb_thick = fw->title_thickness; nbuttons = fw->nr_left_buttons + fw->nr_right_buttons; nbuttons_big = 0; b_length = tb_thick; t_length = tb_length - nbuttons * b_length; if (nbuttons > 0 && t_length < MIN_WINDOW_TITLE_LENGTH) { int diff = MIN_WINDOW_TITLE_LENGTH - t_length; int pixels = diff / nbuttons; b_length -= pixels; t_length += nbuttons * pixels; nbuttons_big = nbuttons - (MIN_WINDOW_TITLE_LENGTH - t_length); t_length = MIN_WINDOW_TITLE_LENGTH; } if (b_length < MIN_WINDOW_TITLEBUTTON_LENGTH) { /* don't draw the buttons */ nbuttons = 0; nbuttons_big = 0; b_length = 0; t_length = tb_length; } if (t_length < 0) { t_length = 0; } fw->title_length = t_length; /* prepare variables */ if (HAS_VERTICAL_TITLE(fw)) { tb_y = b.top_left.height; br_sub = (diff_g != NULL) ? diff_g->height : 0; if (GET_TITLE_DIR(fw) == DIR_W) { tb_x = b.top_left.width; } else { tb_x = frame_g->width - b.bottom_right.width - tb_thick; if (diff_g != NULL) { tb_x -= diff_g->width; } } padd_coord = &tb_y; b_w = tb_thick; b_h = b_length; t_w = tb_thick; t_h = t_length; b_l = &b_h; tb_w = tb_thick; tb_h = tb_length; } else { tb_x = b.top_left.width; br_sub = (diff_g != NULL) ? diff_g->width : 0; if (GET_TITLE_DIR(fw) == DIR_N) { tb_y = b.top_left.height; } else { tb_y = frame_g->height - b.bottom_right.height - tb_thick; if (diff_g != NULL) { tb_y -= diff_g->height; } } padd_coord = &tb_x; b_w = b_length; b_h = tb_thick; t_w = t_length; t_h = tb_thick; b_l = &b_w; tb_w = tb_length; tb_h = tb_thick; } if (fw->title_text_rotation == ROTATION_270 || fw->title_text_rotation == ROTATION_180) { revert_button = True; } /* configure left buttons */ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if ((revert_button && !(i & 1)) || (!revert_button && (i & 1)) || FW_W_BUTTON(fw, i) == None) { continue; } if (b_length <= 0) { title_layout->button_g[i].x = -1; title_layout->button_g[i].y = -1; title_layout->button_g[i].width = 1; title_layout->button_g[i].height = 1; } else { title_layout->button_g[i].x = tb_x; title_layout->button_g[i].y = tb_y; title_layout->button_g[i].width = b_w; title_layout->button_g[i].height = b_h; } *padd_coord += b_length; nbuttons_big--; if (nbuttons_big == 0) { b_length--; (*b_l)--; } } /* configure title */ if (t_length == 0) { title_layout->title_g.x = -1; title_layout->title_g.y = -1; title_layout->title_g.width = 1; title_layout->title_g.height = 1; } else { title_layout->title_g.x = tb_x; title_layout->title_g.y = tb_y; title_layout->title_g.width = t_w; title_layout->title_g.height = t_h; } *padd_coord += t_length; /* configure right buttons */ *padd_coord -= br_sub; for (i = NUMBER_OF_TITLE_BUTTONS-1; i > -1; i--) { if ((revert_button && (i & 1)) || (!revert_button && !(i & 1)) || FW_W_BUTTON(fw, i) == None) { continue; } if (b_length <= 0) { title_layout->button_g[i].x = -1; title_layout->button_g[i].y = -1; title_layout->button_g[i].width = 1; title_layout->button_g[i].height = 1; } else { title_layout->button_g[i].x = tb_x; title_layout->button_g[i].y = tb_y; title_layout->button_g[i].width = b_w; title_layout->button_g[i].height = b_h; } *padd_coord += b_length; nbuttons_big--; if (nbuttons_big == 0) { b_length--; (*b_l)--; } } return; } void frame_get_sidebar_geometry( FvwmWindow *fw, DecorFaceStyle *borderstyle, rectangle *frame_g, rectangle *ret_g, Bool *ret_has_x_marks, Bool *ret_has_y_marks) { int min_w; size_borders b; ret_g->x = 0; ret_g->y = 0; ret_g->width = 0; ret_g->height = 0; *ret_has_x_marks = False; *ret_has_y_marks = False; if (HAS_NO_BORDER(fw)) { return; } /* get the corner size */ if (!HAS_HANDLES(fw)) { *ret_has_x_marks = False; *ret_has_y_marks = False; } else if (borderstyle == NULL) { if (fw->decor_state.parts_drawn & PART_X_HANDLES) { *ret_has_x_marks = True; } if (fw->decor_state.parts_drawn & PART_Y_HANDLES) { *ret_has_y_marks = True; } } else if (!DFS_HAS_HIDDEN_HANDLES(*borderstyle)) { *ret_has_x_marks = True; *ret_has_y_marks = True; } ret_g->x = fw->corner_width; ret_g->y = fw->corner_width; min_w = 2 * fw->corner_width + 4; /* limit by available space, remove handle marks if necessary */ if (frame_g->width < min_w) { ret_g->x = frame_g->width / 3; *ret_has_y_marks = False; } if (frame_g->height < min_w) { ret_g->y = frame_g->height / 3; *ret_has_x_marks = False; } get_window_borders_no_title(fw, &b); if (ret_g->x < b.top_left.width) { ret_g->x = b.top_left.width; } if (ret_g->y < b.top_left.height) { ret_g->y = b.top_left.height; } /* length of the side bars */ ret_g->width = frame_g->width - 2 * ret_g->x; ret_g->height = frame_g->height - 2 * ret_g->y; return; } int frame_window_id_to_context( FvwmWindow *fw, Window w, int *ret_num) { int context = C_ROOT; *ret_num = -1; if (fw == NULL || w == None) { return C_ROOT; } if (w == FW_W_TITLE(fw)) { context = C_TITLE; } else if (Scr.EwmhDesktop && (w == FW_W(Scr.EwmhDesktop) || w == FW_W_PARENT(Scr.EwmhDesktop) || w == FW_W_FRAME(Scr.EwmhDesktop))) { context = C_EWMH_DESKTOP; } else if (w == FW_W(fw) || w == FW_W_PARENT(fw) || w == FW_W_FRAME(fw)) { context = C_WINDOW; } else if (w == FW_W_ICON_TITLE(fw) || w == FW_W_ICON_PIXMAP(fw)) { context = C_ICON; } else if (w == FW_W_CORNER(fw, 0)) { *ret_num = 0; context = C_F_TOPLEFT; } else if (w == FW_W_CORNER(fw, 1)) { *ret_num = 1; context = C_F_TOPRIGHT; } else if (w == FW_W_CORNER(fw, 2)) { *ret_num = 2; context = C_F_BOTTOMLEFT; } else if (w == FW_W_CORNER(fw, 3)) { *ret_num = 3; context = C_F_BOTTOMRIGHT; } else if (w == FW_W_SIDE(fw, 0)) { *ret_num = 0; context = C_SB_TOP; } else if (w == FW_W_SIDE(fw, 1)) { *ret_num = 1; context = C_SB_RIGHT; } else if (w == FW_W_SIDE(fw, 2)) { *ret_num = 2; context = C_SB_BOTTOM; } else if (w == FW_W_SIDE(fw, 3)) { *ret_num = 3; context = C_SB_LEFT; } else { int i; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (w == FW_W_BUTTON(fw, i) && ((!(i & 1) && i / 2 < Scr.nr_left_buttons) || ( (i & 1) && i / 2 < Scr.nr_right_buttons))) { context = (1 << i) * C_L1; *ret_num = i; break; } } } if (!HAS_HANDLES(fw) && (context & (C_SIDEBAR | C_FRAME))) { context = C_SIDEBAR; } return context; } /* Creates a structure that must be passed to frame_move_resize(). The * structure *must* be deleted with frame_free_move_resize_args() as soon as the * move or resize operation is finished. Prepares the window for a move/resize * operation. * * Arguments: * fw * The window to move or resize. * mr_mode * The mode of operation: * FRAME_MR_SETUP: setup the frame * FRAME_MR_FORCE_SETUP: same, but forces all updates * FRAME_MR_OPAQUE: resize the frame in an opaque fashion * FRAME_MR_SHRINK: shrink the client window (useful for shading only) * FRAME_MR_SCROLL: scroll the client window (useful for shading only) * start_g * The initial geometry of the frame. If a NULL pointer is passed, the * frame_g member of the window is used instead. * end_g * The desired new geometry of the frame. * anim_steps * The number of animation steps in between * = 0: The operation is finished in a single step. * > 0: The given number of steps are drawn in between. * < 0: Each step resizes the window by the given number of pixels. * (the sign of the number is flipped first). * This argument is used only with FRAME_MR_SHRINK and FRAME_MR_SCROLL. */ frame_move_resize_args frame_create_move_resize_args( FvwmWindow *fw, frame_move_resize_mode mr_mode, rectangle *start_g, rectangle *end_g, int anim_steps, int shade_dir) { mr_args_internal *mra; Bool dummy; Bool rc; int whdiff; int xydiff; int diff; /* set some variables */ mra = (mr_args_internal *)safecalloc(1, sizeof(mr_args_internal)); memset(mra, 0, sizeof(*mra)); if (mr_mode & FRAME_MR_DONT_DRAW) { mr_mode &= ~FRAME_MR_DONT_DRAW; mra->flags.do_not_draw = 1; } else { mra->flags.do_not_draw = 0; } if (mr_mode == FRAME_MR_SETUP_BY_APP) { mr_mode = FRAME_MR_SETUP; mra->flags.do_set_bit_gravity = 0; } else { mra->flags.do_set_bit_gravity = 1; } if (mr_mode == FRAME_MR_FORCE_SETUP_NO_W) { mr_mode = FRAME_MR_FORCE_SETUP; mra->flags.do_not_configure_client = 1; } mra->mode = mr_mode; mra->shade_dir = (direction_t)shade_dir; mra->w_with_focus = (fw == get_focus_window()) ? FW_W(fw) : None; /* calculate various geometries */ if (!IS_SHADED(fw)) { rc = XGetGeometry( dpy, FW_W(fw), &JunkRoot, &mra->client_g.x, &mra->client_g.y, (unsigned int*)&mra->client_g.width, (unsigned int*)&mra->client_g.height, (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth); if (rc == True) { rc = XTranslateCoordinates( dpy, FW_W_PARENT(fw), Scr.Root, mra->client_g.x, mra->client_g.y, &mra->client_g.x, &mra->client_g.y, &JunkChild); } if (rc == False) { /* Can only happen if the window died */ get_client_geometry(fw, &mra->client_g); } } else { /* If the window was reisez while shaded the client window * will not have been resized. Use the frame to get the * geometry */ get_client_geometry(fw, &mra->client_g); } get_window_borders(fw, &mra->b_g); get_window_borders_no_title(fw, &mra->b_no_title_g); mra->start_g = (start_g != NULL) ? *start_g : fw->g.frame; frame_get_sidebar_geometry( fw, NULL, &mra->start_g, &mra->curr_sidebar_g, &dummy, &dummy); mra->end_g = *end_g; mra->current_g = mra->start_g; mra->next_g = mra->end_g; mra->curr_titlebar_compression = frame_get_titlebar_compression(fw, &mra->start_g); fvwmrect_subtract_rectangles( &mra->delta_g, &mra->end_g, &mra->start_g); /* calcuate the number of animation steps */ switch (mra->mode) { case FRAME_MR_SHRINK: case FRAME_MR_SCROLL: whdiff = max(abs(mra->delta_g.width), abs(mra->delta_g.height)); xydiff = max(abs(mra->delta_g.x), abs(mra->delta_g.y)); diff = max(whdiff, xydiff); if (diff == 0) { mra->anim_steps = 0; } else if (anim_steps < 0) { mra->anim_steps = -(diff - 1) / anim_steps; } else if (anim_steps > 0 && anim_steps >= diff) { mra->anim_steps = diff - 1; } else { mra->anim_steps = anim_steps; } mra->anim_steps++; break; case FRAME_MR_FORCE_SETUP: case FRAME_MR_SETUP: case FRAME_MR_OPAQUE: default: mra->anim_steps = 1; break; } /* various flags */ mra->flags.was_moved = 0; mra->step_flags.was_hidden = (frame_is_parent_hidden(fw, &mra->start_g) == True); mra->flags.is_setup = (mra->mode == FRAME_MR_FORCE_SETUP || mra->mode == FRAME_MR_SETUP); mra->flags.do_force = (mra->mode == FRAME_MR_FORCE_SETUP); mra->flags.is_shading = !(mra->flags.is_setup || mra->mode == FRAME_MR_OPAQUE); mra->flags.do_update_shape = (FShapesSupported && mra->flags.is_shading && fw->wShaped); /* Lazy shading does not draw the hadle marks. Disable them in the * window flags if necessary. Restores the marks when mr_args are * freed. Lazy shading is considerably faster but causes funny looks * if either the border uses a tiled pixmap background. */ mra->flags.had_handles = HAS_HANDLES(fw); mra->flags.is_lazy_shading = frame_get_shading_laziness(fw, mra); mra->trans_parts = border_get_transparent_decorations_part(fw); if (mra->flags.is_lazy_shading) { SET_HAS_HANDLES(fw, 0); } /* Set gravities for the window parts. */ frame_get_resize_decor_gravities( &mra->grav, GET_TITLE_DIR(fw), mra->mode, &mra->delta_g); if (mra->flags.is_setup && mra->delta_g.x == 0 && mra->delta_g.y == 0 && mra->delta_g.width == 0 && mra->delta_g.height == 0) { frame_decor_gravities_type grav; /* The caller has already set the frame geometry. Use * StaticGravity so the sub windows are not moved to funny * places. */ grav.decor_grav = StaticGravity; grav.title_grav = StaticGravity; grav.lbutton_grav = StaticGravity; grav.rbutton_grav = StaticGravity; grav.parent_grav = StaticGravity; grav.client_grav = StaticGravity; frame_set_decor_gravities( fw, &grav, (mra->flags.do_set_bit_gravity) ? 1 : 0); mra->flags.do_restore_gravity = 1; mra->flags.do_force = 1; } else { frame_set_decor_gravities( fw, &mra->grav, (mra->flags.do_set_bit_gravity) ? 1 : 0); } frame_reparent_hide_windows(FW_W_FRAME(fw)); return (frame_move_resize_args)mra; } /* Changes the final_geometry in a frame_move_resize_args structure. This is * useful during opaque resize operations to avoid creating and destroying the * args for each animation step. * * If FRAME_MR_SHRINK or FRAME_MR_SCROLL was used to greate the mr_args, the * function does nothing. */ void frame_update_move_resize_args( frame_move_resize_args mr_args, rectangle *end_g) { mr_args_internal *mra; mra = (mr_args_internal *)mr_args; mra->end_g = *end_g; fvwmrect_subtract_rectangles( &mra->delta_g, &mra->end_g, &mra->start_g); return; } /* Destroys the structure allocated with frame_create_move_resize_args(). Does * some clean up operations on the modified window first. */ void frame_free_move_resize_args( FvwmWindow *fw, frame_move_resize_args mr_args) { mr_args_internal *mra; mra = (mr_args_internal *)mr_args; SET_HAS_HANDLES(fw, mra->flags.had_handles); fw->g.frame = mra->end_g; if (mra->flags.is_lazy_shading) { border_draw_decorations( fw, PART_ALL, (mra->w_with_focus != None) ? True : False, True, CLEAR_ALL, &mra->current_g, &mra->end_g); } else if (mra->trans_parts != PART_NONE) { border_draw_decorations( fw, mra->trans_parts, (mra->w_with_focus != None) ? True : False, True, CLEAR_ALL, &mra->current_g, &mra->end_g); } update_absolute_geometry(fw); frame_reparent_hide_windows(Scr.NoFocusWin); if (mra->w_with_focus != None) { /* domivogt (28-Dec-1999): For some reason the XMoveResize() on * the frame window removes the input focus from the client * window. I have no idea why, but if we explicitly restore * the focus here everything works fine. */ FOCUS_SET(mra->w_with_focus); } if (mra->flags.do_update_shape) { /* unset shape */ FShapeCombineMask( dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None, FShapeSet); } frame_setup_shape(fw, mra->end_g.width, mra->end_g.height, fw->wShaped); if (mra->flags.do_restore_gravity) { mra->grav.client_grav = fw->hints.win_gravity; frame_set_decor_gravities( fw, &mra->grav, (mra->flags.do_set_bit_gravity) ? 2 : 0); } else { frame_restore_client_gravities(fw); } if (!IS_SHADED(fw) && mra->flags.was_moved) { SendConfigureNotify( fw, fw->g.frame.x, fw->g.frame.y, fw->g.frame.width, fw->g.frame.height, 0, True); mra->flags.was_moved = 0; } focus_grab_buttons_on_layer(fw->layer); /* free the memory */ free(mr_args); return; } void frame_move_resize( FvwmWindow *fw, frame_move_resize_args mr_args) { mr_args_internal *mra; Bool is_grabbed = False; int i; mra = (mr_args_internal *)mr_args; /* freeze the cursor shape; otherwise it may flash to a different shape * during the animation */ if (mra->anim_steps > 1) { is_grabbed = GrabEm(None, GRAB_FREEZE_CURSOR); } /* animation */ for (i = 1; i <= mra->anim_steps; i++, frame_next_move_resize_args(mra)) { mra->current_step = i; frame_move_resize_step(fw, mra); } if (is_grabbed == True) { UngrabEm(GRAB_FREEZE_CURSOR); } return; } /*********************************************************************** * * Procedure: * frame_setup_window - set window sizes * * Inputs: * fw - the FvwmWindow pointer * x - the x coordinate of the upper-left outer corner of the frame * y - the y coordinate of the upper-left outer corner of the frame * w - the width of the frame window w/o border * h - the height of the frame window w/o border * * Special Considerations: * This routine will check to make sure the window is not completely * off the display, if it is, it'll bring some of it back on. * * The fw->frame_XXX variables should NOT be updated with the * values of x,y,w,h prior to calling this routine, since the new * values are compared against the old to see whether a synthetic * ConfigureNotify event should be sent. (It should be sent if the * window was moved but not resized.) * ************************************************************************/ void frame_setup_window( FvwmWindow *fw, int x, int y, int w, int h, Bool do_send_configure_notify) { rectangle g; g.x = x; g.y = y; g.width = w; g.height = h; __frame_setup_window(fw, &g, do_send_configure_notify, False, False); return; } void frame_setup_window_app_request( FvwmWindow *fw, int x, int y, int w, int h, Bool do_send_configure_notify) { rectangle g; g.x = x; g.y = y; g.width = w; g.height = h; __frame_setup_window(fw, &g, do_send_configure_notify, False, True); return; } void frame_force_setup_window( FvwmWindow *fw, int x, int y, int w, int h, Bool do_send_configure_notify) { rectangle g; g.x = x; g.y = y; g.width = w; g.height = h; __frame_setup_window(fw, &g, do_send_configure_notify, True, False); return; } /**************************************************************************** * * Sets up the shaped window borders * ****************************************************************************/ void frame_setup_shape(FvwmWindow *fw, int w, int h, int shape_mode) { XRectangle rect; rectangle r; size_borders b; if (!FShapesSupported) { return; } if (fw->wShaped != shape_mode) { fw->wShaped = shape_mode; frame_reshape_border(fw); } if (!shape_mode) { /* unset shape */ FShapeCombineMask( dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, None, FShapeSet); } else { /* shape the window */ get_window_borders(fw, &b); FShapeCombineShape( dpy, FW_W_FRAME(fw), FShapeBounding, b.top_left.width, b.top_left.height, FW_W(fw), FShapeBounding, FShapeSet); if (FW_W_TITLE(fw)) { /* windows w/ titles */ r.width = w; r.height = h; get_title_geometry(fw, &r); rect.x = r.x; rect.y = r.y; rect.width = r.width; rect.height = r.height; FShapeCombineRectangles( dpy, FW_W_FRAME(fw), FShapeBounding, 0, 0, &rect, 1, FShapeUnion, Unsorted); } } return; } /* ---------------------------- builtin commands --------------------------- */