diff --git a/src/Makefile.am b/src/Makefile.am index 065efc661..b4faf06dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -55,6 +55,8 @@ metacity_SOURCES= \ main.h \ screen.c \ screen.h \ + session.c \ + session.h \ theme.c \ theme.h \ uislave.c \ diff --git a/src/display.c b/src/display.c index 51712250b..196224b3c 100644 --- a/src/display.c +++ b/src/display.c @@ -86,7 +86,11 @@ meta_display_open (const char *name) "_NET_WM_STATE_MAXIMIZED_HORZ", "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_DESKTOP", - "_NET_NUMBER_OF_DESKTOPS" + "_NET_NUMBER_OF_DESKTOPS", + "WM_CHANGE_STATE", + "SM_CLIENT_ID", + "WM_CLIENT_LEADER", + "WM_WINDOW_ROLE" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -136,6 +140,10 @@ meta_display_open (const char *name) display->atom_net_wm_state_maximized_vert = atoms[10]; display->atom_net_wm_desktop = atoms[11]; display->atom_net_number_of_desktops = atoms[12]; + display->atom_wm_change_state = atoms[13]; + display->atom_sm_client_id = atoms[14]; + display->atom_wm_client_leader = atoms[15]; + display->atom_wm_window_role = atoms[16]; screens = NULL; i = 0; @@ -175,6 +183,13 @@ meta_display_open (const char *name) display->last_button_xwindow = None; display->last_button_num = 0; display->is_double_click = FALSE; + + /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK + */ + display->leader_window = + XCreateSimpleWindow (display->xdisplay, + ((MetaScreen*)display->screens->data)->xroot, + -100, -100, 1, 1, 0, 0, 0); /* Now manage all existing windows */ tmp = display->screens; @@ -241,6 +256,8 @@ meta_display_close (MetaDisplay *display) * unregister windows */ g_hash_table_destroy (display->window_ids); + + XDestroyWindow (display->xdisplay, display->leader_window); meta_event_queue_free (display->events); XCloseDisplay (display->xdisplay); diff --git a/src/display.h b/src/display.h index bc24b28e2..e1704cec0 100644 --- a/src/display.h +++ b/src/display.h @@ -43,6 +43,8 @@ struct _MetaDisplay char *name; Display *xdisplay; + Window leader_window; + Atom atom_net_wm_name; Atom atom_wm_protocols; Atom atom_wm_take_focus; @@ -56,6 +58,10 @@ struct _MetaDisplay Atom atom_net_wm_state_maximized_vert; Atom atom_net_wm_desktop; Atom atom_net_number_of_desktops; + Atom atom_wm_change_state; + Atom atom_sm_client_id; + Atom atom_wm_client_leader; + Atom atom_wm_window_role; /* This is the actual window from focus events, * not the one we last set diff --git a/src/frame.c b/src/frame.c index 7d20aa230..9ec4734d9 100644 --- a/src/frame.c +++ b/src/frame.c @@ -79,61 +79,77 @@ meta_frame_init_info (MetaFrame *frame, info->current_control_state = META_STATE_PRELIGHT; } -static void -meta_frame_calc_initial_pos (MetaFrame *frame, - int child_root_x, int child_root_y) + +/* returns values suitable for meta_window_move */ +void +meta_frame_adjust_for_gravity (int win_gravity, + int frame_width, + int frame_height, + MetaFrameGeometry *fgeom, + int child_root_x, + int child_root_y, + int *win_root_x, + int *win_root_y) { - MetaWindow *window; + int x, y; + + /* NW coordinate of the frame. We should just + * compute NW coordinate to return from the start, + * but I wrote it this way first and am now lazy + */ + x = 0; + y = 0; - window = frame->window; - - switch (window->size_hints.win_gravity) + switch (win_gravity) { case NorthWestGravity: - frame->rect.x = child_root_x; - frame->rect.y = child_root_y; + x = child_root_x; + y = child_root_y; break; case NorthGravity: - frame->rect.x = child_root_x - frame->rect.width / 2; - frame->rect.y = child_root_y; + x = child_root_x - frame_width / 2; + y = child_root_y; break; case NorthEastGravity: - frame->rect.x = child_root_x - frame->rect.width; - frame->rect.y = child_root_y; + x = child_root_x - frame_width; + y = child_root_y; break; case WestGravity: - frame->rect.x = child_root_x; - frame->rect.y = child_root_y - frame->rect.height / 2; + x = child_root_x; + y = child_root_y - frame_height / 2; break; case CenterGravity: - frame->rect.x = child_root_x - frame->rect.width / 2; - frame->rect.y = child_root_y - frame->rect.height / 2; + x = child_root_x - frame_width / 2; + y = child_root_y - frame_height / 2; break; case EastGravity: - frame->rect.x = child_root_x - frame->rect.width; - frame->rect.y = child_root_y - frame->rect.height / 2; + x = child_root_x - frame_width; + y = child_root_y - frame_height / 2; break; case SouthWestGravity: - frame->rect.x = child_root_x; - frame->rect.y = child_root_y - frame->rect.height; + x = child_root_x; + y = child_root_y - frame_height; break; case SouthGravity: - frame->rect.x = child_root_x - frame->rect.width / 2; - frame->rect.y = child_root_y - frame->rect.height; + x = child_root_x - frame_width / 2; + y = child_root_y - frame_height; break; case SouthEastGravity: - frame->rect.x = child_root_x - frame->rect.width; - frame->rect.y = child_root_y - frame->rect.height; + x = child_root_x - frame_width; + y = child_root_y - frame_height; break; case StaticGravity: default: - frame->rect.x = child_root_x - frame->child_x; - frame->rect.y = child_root_y - frame->child_y; + x = child_root_x - fgeom->left_width; + y = child_root_y - fgeom->top_height; break; } + + *win_root_x = x + fgeom->left_width; + *win_root_y = y + fgeom->top_height; } -static void +void meta_frame_calc_geometry (MetaFrame *frame, int child_width, int child_height, MetaFrameGeometry *geomp) @@ -143,20 +159,22 @@ meta_frame_calc_geometry (MetaFrame *frame, MetaWindow *window; /* Remember this is called from the constructor - * pre-window-creation. + * pre-X-window-creation. */ window = frame->window; - frame->rect.width = child_width; - - if (window->shaded) - frame->rect.height = 0; - else - frame->rect.height = child_height; + /* frame->rect isn't useful yet */ meta_frame_init_info (frame, &info); + /* these were from frame->rect so fix them up */ + info.width = child_width; + if (window->shaded) + info.height = 0; + else + info.height = child_height; + if (!frame->theme_acquired) frame->theme_data = window->screen->engine->acquire_frame (&info); @@ -172,19 +190,6 @@ meta_frame_calc_geometry (MetaFrame *frame, window->screen->engine->fill_frame_geometry (&info, &geom, frame->theme_data); - - frame->child_x = geom.left_width; - frame->child_y = geom.top_height; - frame->right_width = geom.right_width; - frame->bottom_height = geom.bottom_height; - - frame->rect.width = frame->rect.width + geom.left_width + geom.right_width; - frame->rect.height = frame->rect.height + geom.top_height + geom.bottom_height; - - meta_debug_spew ("Added top %d and bottom %d totalling %d over child height %d\n", - geom.top_height, geom.bottom_height, frame->rect.height, child_height); - - frame->bg_pixel = geom.background_pixel; *geomp = geom; } @@ -232,7 +237,6 @@ meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; - MetaFrameGeometry geom; if (window->frame) return; @@ -245,25 +249,14 @@ meta_window_ensure_frame (MetaWindow *window) frame->grab = NULL; frame->current_control = META_FRAME_CONTROL_NONE; frame->tooltip_timeout = 0; - - /* This fills in frame->rect as well. */ - meta_frame_calc_geometry (frame, - window->rect.width, - window->rect.height, - &geom); - meta_frame_calc_initial_pos (frame, window->rect.x, window->rect.y); - - meta_verbose ("Will create frame %d,%d %dx%d around window %s %d,%d %dx%d with child position inside frame %d,%d and gravity %d\n", - frame->rect.x, frame->rect.y, - frame->rect.width, frame->rect.height, - window->desc, - window->rect.x, window->rect.y, - window->rect.width, window->rect.height, - frame->child_x, frame->child_y, - window->size_hints.win_gravity); - - attrs.background_pixel = frame->bg_pixel; + frame->rect = window->rect; + frame->child_x = 0; + frame->child_y = 0; + frame->bottom_height = 0; + frame->right_width = 0; + frame->bg_pixel = 0; + attrs.event_mask = EVENT_MASK; frame->xwindow = XCreateWindow (window->display->xdisplay, @@ -276,10 +269,10 @@ meta_window_ensure_frame (MetaWindow *window) window->depth, InputOutput, window->xvisual, - CWBackPixel | CWEventMask, + CWEventMask, &attrs); - meta_verbose ("Frame is 0x%lx\n", frame->xwindow); + meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); meta_display_register_x_window (window->display, &frame->xwindow, window); @@ -299,21 +292,15 @@ meta_window_ensure_frame (MetaWindow *window) XReparentWindow (window->display->xdisplay, window->xwindow, frame->xwindow, - frame->child_x, - frame->child_y); + 0, 0); meta_error_trap_pop (window->display); - - /* Update window's location */ - window->rect.x = frame->child_x; - window->rect.y = frame->child_y; /* stick frame to the window */ window->frame = frame; - /* Put our state back where it should be */ - meta_window_queue_calc_showing (window); - - /* Ungrab server */ + /* Ungrab server (FIXME after fixing Pango not to lock us up, + * we need to recalc geometry before ungrabbing) + */ meta_display_ungrab (window->display); } @@ -367,82 +354,24 @@ meta_window_destroy_frame (MetaWindow *window) meta_window_queue_calc_showing (window); } -/* Just a chunk of process_configure_event in window.c, - * moved here since it's the part that deals with - * the frame. - */ void -meta_frame_child_configure_request (MetaFrame *frame) +meta_frame_sync_to_window (MetaFrame *frame) { - MetaFrameGeometry geom; - - /* This fills in frame->rect as well. */ - meta_frame_calc_geometry (frame, - frame->window->size_hints.width, - frame->window->size_hints.height, - &geom); - - meta_frame_calc_initial_pos (frame, - frame->window->size_hints.x, - frame->window->size_hints.y); - - set_background_none (frame); - XMoveResizeWindow (frame->window->display->xdisplay, - frame->xwindow, - frame->rect.x, - frame->rect.y, - frame->rect.width, - frame->rect.height); - set_background_color (frame); -} - -void -meta_frame_recalc_now (MetaFrame *frame) -{ - int old_child_x, old_child_y; - MetaFrameGeometry geom; - - old_child_x = frame->child_x; - old_child_y = frame->child_y; - - /* This fills in frame->rect as well. */ - meta_frame_calc_geometry (frame, - frame->window->rect.width, - frame->window->rect.height, - &geom); - - /* See if we need to move the frame to keep child in - * a constant position - */ - if (old_child_x != frame->child_x) - frame->rect.x += (frame->child_x - old_child_x); - if (old_child_y != frame->child_y) - frame->rect.y += (frame->child_y - old_child_y); - - set_background_none (frame); - XMoveResizeWindow (frame->window->display->xdisplay, - frame->xwindow, - frame->rect.x, - frame->rect.y, - frame->rect.width, - frame->rect.height); - set_background_color (frame); - - meta_verbose ("Frame of %s recalculated to %d,%d %d x %d child %d,%d\n", - frame->window->desc, frame->rect.x, frame->rect.y, + meta_verbose ("Syncing frame geometry %d,%d %dx%d pixel %ld\n", + frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, - frame->child_x, frame->child_y); - + frame->bg_pixel); + set_background_none (frame); + XMoveResizeWindow (frame->window->display->xdisplay, + frame->xwindow, + frame->rect.x, + frame->rect.y, + frame->rect.width, + frame->rect.height); + set_background_color (frame); meta_frame_queue_draw (frame); } -void -meta_frame_queue_recalc (MetaFrame *frame) -{ - /* FIXME, actually queue */ - meta_frame_recalc_now (frame); -} - static void meta_frame_draw_now (MetaFrame *frame, int x, int y, int width, int height) @@ -776,7 +705,7 @@ get_menu_items (MetaFrame *frame, *ops |= (META_MESSAGE_MENU_DELETE | META_MESSAGE_MENU_WORKSPACES | META_MESSAGE_MENU_MINIMIZE); - if (!(info->flags & META_FRAME_CONTROL_MINIMIZE)) + if (!(info->flags & META_FRAME_CONTROL_ICONIFY)) *insensitive |= META_MESSAGE_MENU_MINIMIZE; if (!(info->flags & META_FRAME_CONTROL_DELETE)) diff --git a/src/frame.h b/src/frame.h index c520b1a2a..1e3e52b07 100644 --- a/src/frame.h +++ b/src/frame.h @@ -66,14 +66,25 @@ struct _MetaFrame void meta_window_ensure_frame (MetaWindow *window); void meta_window_destroy_frame (MetaWindow *window); -void meta_frame_child_configure_request (MetaFrame *frame); -void meta_frame_recalc_now (MetaFrame *frame); -void meta_frame_queue_recalc (MetaFrame *frame); void meta_frame_queue_draw (MetaFrame *frame); gboolean meta_frame_event (MetaFrame *frame, XEvent *event); - +/* These three should ONLY be called from meta_window_move_resize_internal */ +void meta_frame_calc_geometry (MetaFrame *frame, + int child_width, + int child_height, + MetaFrameGeometry *geomp); +/* returns values suitable for meta_window_move */ +void meta_frame_adjust_for_gravity (int win_gravity, + int frame_width, + int frame_height, + MetaFrameGeometry *fgeom, + int x, + int y, + int *win_root_x, + int *win_root_y); +void meta_frame_sync_to_window (MetaFrame *frame); #endif diff --git a/src/session.c b/src/session.c new file mode 100644 index 000000000..6986d5f23 --- /dev/null +++ b/src/session.c @@ -0,0 +1,27 @@ +/* Metacity Session Management */ + +/* + * Copyright (C) 2001 Havoc Pennington + * + * 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. + */ + +#include "session.h" + + + + + diff --git a/src/session.h b/src/session.h new file mode 100644 index 000000000..13021df61 --- /dev/null +++ b/src/session.h @@ -0,0 +1,48 @@ +/* Metacity Session Management */ + +/* + * Copyright (C) 2001 Havoc Pennington + * + * 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. + */ + +#ifndef META_SESSION_H +#define META_SESSION_H + +#include "window.h" + +typedef struct _MetaSessionInfo MetaSessionInfo; + +struct _MetaSessionInfo +{ + /* In -geometry format; x, y are affected by gravity, width, height + * are to be multiplied by resize increments, etc. This way we're + * robust against theme changes, client resize inc changes, client + * base size changes, and so on. + */ + MetaRectangle rect; + + /* A per-screen index (_NET_WM_DESKTOP) */ + int workspace; +}; + +MetaSessionInfo* meta_window_lookup_session_info (MetaWindow *window); + +#endif + + + + diff --git a/src/window.c b/src/window.c index 59f4af574..9094fc100 100644 --- a/src/window.c +++ b/src/window.c @@ -27,17 +27,28 @@ #include -static void constrain_size (MetaWindow *window, - int width, - int height, - int *new_width, - int *new_height); +static void constrain_size (MetaWindow *window, + int width, + int height, + int *new_width, + int *new_height); +static void constrain_position (MetaWindow *window, + MetaFrameGeometry *fgeom, + int x, + int y, + int *new_x, + int *new_y); + static int update_size_hints (MetaWindow *window); static int update_title (MetaWindow *window); static int update_protocols (MetaWindow *window); static int update_wm_hints (MetaWindow *window); static int update_net_wm_state (MetaWindow *window); static int update_mwm_hints (MetaWindow *window); +static int update_wm_class (MetaWindow *window); +static int update_transient_for (MetaWindow *window); +static void update_sm_hints (MetaWindow *window); +static int update_role (MetaWindow *window); static int set_wm_state (MetaWindow *window, int state); static void send_configure_notify (MetaWindow *window); @@ -52,6 +63,14 @@ static gboolean process_property_notify (MetaWindow *window, static void meta_window_show (MetaWindow *window); static void meta_window_hide (MetaWindow *window); +static void meta_window_move_resize_internal (MetaWindow *window, + gboolean move, + gboolean resize, + gboolean is_configure_request, + int root_x_nw, + int root_y_nw, + int w, + int h); MetaWindow* meta_window_new (MetaDisplay *display, Window xwindow) @@ -155,6 +174,15 @@ meta_window_new (MetaDisplay *display, Window xwindow) window->has_close_func = TRUE; window->has_minimize_func = TRUE; window->has_maximize_func = TRUE; + + window->res_class = NULL; + window->res_name = NULL; + window->role = NULL; + window->sm_client_id = NULL; + + window->xtransient_for = None; + window->xgroup_leader = None; + window->xclient_leader = None; meta_display_register_x_window (display, &window->xwindow, window); @@ -164,6 +192,10 @@ meta_window_new (MetaDisplay *display, Window xwindow) update_wm_hints (window); update_net_wm_state (window); update_mwm_hints (window); + update_wm_class (window); + update_transient_for (window); + update_sm_hints (window); /* must come after transient_for */ + update_role (window); if (window->initially_iconic) { @@ -171,10 +203,6 @@ meta_window_new (MetaDisplay *display, Window xwindow) window->minimized = TRUE; meta_verbose ("Window %s asked to start out minimized\n", window->desc); } - - meta_window_resize (window, - window->size_hints.width, - window->size_hints.height); /* FIXME we have a tendency to set this then immediately * change it again. @@ -186,7 +214,16 @@ meta_window_new (MetaDisplay *display, Window xwindow) meta_workspace_add_window (window->screen->active_workspace, window); - /* Put our state back where it should be */ + /* Put our state back where it should be, + * passing TRUE for is_configure_request, ICCCM says + * initial map is handled same as configure request + */ + meta_window_move_resize_internal (window, TRUE, TRUE, TRUE, + window->size_hints.x, + window->size_hints.y, + window->size_hints.width, + window->size_hints.height); + meta_window_queue_calc_showing (window); return window; @@ -371,34 +408,19 @@ meta_window_maximize (MetaWindow *window) { if (!window->maximized) { - int x, y; - window->maximized = TRUE; - /* save size/pos */ + /* save size/pos as appropriate args for move_resize */ window->saved_rect = window->rect; if (window->frame) { window->saved_rect.x += window->frame->rect.x; window->saved_rect.y += window->frame->rect.y; } - - /* find top left corner */ - x = window->screen->active_workspace->workarea.x; - y = window->screen->active_workspace->workarea.y; - if (window->frame) - { - x += window->frame->child_x; - y += window->frame->child_y; - } - - /* resize to current size with new maximization constraint, - * and move to top-left corner + /* move_resize with new maximization constraints */ - - meta_window_move_resize (window, x, y, - window->rect.width, window->rect.height); + meta_window_queue_move_resize (window); } } @@ -423,8 +445,7 @@ meta_window_shade (MetaWindow *window) if (!window->shaded) { window->shaded = TRUE; - if (window->frame) - meta_frame_queue_recalc (window->frame); + meta_window_queue_move_resize (window); meta_window_queue_calc_showing (window); } } @@ -435,9 +456,11 @@ meta_window_unshade (MetaWindow *window) if (window->shaded) { window->shaded = FALSE; - if (window->frame) - meta_frame_queue_recalc (window->frame); + meta_window_queue_move_resize (window); meta_window_queue_calc_showing (window); + /* focus the window */ + /* FIXME CurrentTime is bogus */ + meta_window_focus (window, CurrentTime); } } @@ -445,17 +468,29 @@ static void meta_window_move_resize_internal (MetaWindow *window, gboolean move, gboolean resize, + gboolean is_configure_request, int root_x_nw, int root_y_nw, int w, int h) -{ +{ + XWindowChanges values; + unsigned int mask; + gboolean need_configure_notify; + MetaFrameGeometry fgeom; + if (resize) meta_verbose ("Resizing %s to %d x %d\n", window->desc, w, h); if (move) meta_verbose ("Moving %s to %d,%d\n", window->desc, root_x_nw, root_y_nw); + + + /* remember that root_x_nw, root_y_nw are bogus if not moving, + * and w, h are bogus if not resizing + */ + if (resize) { constrain_size (window, w, h, &w, &h); @@ -468,24 +503,78 @@ meta_window_move_resize_internal (MetaWindow *window, window->rect.height = h; } + if (window->frame) + { + int new_w, new_h; + + meta_frame_calc_geometry (window->frame, + window->rect.width, + window->rect.height, + &fgeom); + + new_w = window->rect.width + fgeom.left_width + fgeom.right_width; + + if (window->shaded) + new_h = fgeom.top_height; + else + new_h = window->rect.height + fgeom.top_height + fgeom.bottom_height; + + /* FIXME could check to avoid XResizeWindow on frame */ + + window->frame->rect.width = new_w; + window->frame->rect.height = new_h; + + meta_verbose ("Calculated frame size %dx%d\n", + window->frame->rect.width, + window->frame->rect.height); + } + if (move) { + if (is_configure_request && window->frame) + { + meta_frame_adjust_for_gravity (window->size_hints.win_gravity, + window->frame->rect.width, + window->frame->rect.height, + &fgeom, + root_x_nw, + root_y_nw, + &root_x_nw, + &root_y_nw); + + meta_verbose ("Compensated position for gravity, new pos %d,%d\n", + root_x_nw, root_y_nw); + } + + constrain_position (window, + window->frame ? &fgeom : NULL, + root_x_nw, root_y_nw, + &root_x_nw, &root_y_nw); + + meta_verbose ("Constrained position to %d,%d\n", + root_x_nw, root_y_nw); + if (window->frame) { int new_x, new_y; - new_x = root_x_nw - window->frame->child_x; - new_y = root_y_nw - window->frame->child_y; + new_x = root_x_nw - fgeom.left_width; + new_y = root_y_nw - fgeom.top_height; if (new_x == window->frame->rect.x && - new_y == window->frame->rect.y) + new_y == window->frame->rect.y && + window->rect.x == fgeom.left_width && + window->rect.y == fgeom.top_height) move = FALSE; window->frame->rect.x = new_x; window->frame->rect.y = new_y; - /* window->rect.x, window->rect.y remain relative to frame, + + /* window->rect.x, window->rect.y are relative to frame, * remember they are the server coords */ + window->rect.x = fgeom.left_width; + window->rect.y = fgeom.top_height; } else { @@ -498,47 +587,61 @@ meta_window_move_resize_internal (MetaWindow *window, } } + /* Fill in other frame member variables */ + if (window->frame) + { + window->frame->child_x = fgeom.left_width; + window->frame->child_y = fgeom.top_height; + window->frame->right_width = fgeom.right_width; + window->frame->bottom_height = fgeom.bottom_height; + window->frame->bg_pixel = fgeom.background_pixel; + } + + /* If this is a configure request and we change nothing, then we + * must send configure notify. In all cases we must send configure + * notify if we don't resize. ICCCM 4.1.5 + */ + need_configure_notify = + (!resize) || + (is_configure_request && !(move || resize || window->border_width != 0)); + /* Sync our new size/pos with X as efficiently as possible */ - if (move && window->frame) - { - XMoveWindow (window->display->xdisplay, - window->frame->xwindow, - window->frame->rect.x, - window->frame->rect.y); - } - - meta_error_trap_push (window->display); - if ((move && window->frame == NULL) && resize) - { - XMoveResizeWindow (window->display->xdisplay, - window->xwindow, - window->rect.x, - window->rect.y, - window->rect.width, - window->rect.height); - } - else if (move && window->frame == NULL) - { - XMoveWindow (window->display->xdisplay, - window->xwindow, - window->rect.x, - window->rect.y); - } - else if (resize) - { - XResizeWindow (window->display->xdisplay, - window->xwindow, - w, h); - - } - meta_error_trap_pop (window->display); + values.border_width = 0; + values.x = window->rect.x; + values.y = window->rect.y; + values.width = window->rect.width; + values.height = window->rect.height; + mask = 0; + if (is_configure_request && window->border_width != 0) + mask |= CWBorderWidth; /* must force to 0 */ if (move) - send_configure_notify (window); + mask |= (CWX | CWY); + if (resize) + mask |= (CWWidth | CWHeight); - if (window->frame && resize) - meta_frame_queue_recalc (window->frame); + if (mask != 0) + { + meta_verbose ("Syncing new geometry to client, border: %s pos: %s size: %s\n", + mask & CWBorderWidth ? "true" : "false", + mask & CWX ? "true" : "false", + mask & CWWidth ? "true" : "false"); + + meta_error_trap_push (window->display); + XConfigureWindow (window->display->xdisplay, + window->xwindow, + mask, + &values); + meta_error_trap_pop (window->display); + } + + /* Now do the frame */ + if (window->frame) + meta_frame_sync_to_window (window->frame); + + if (need_configure_notify) + send_configure_notify (window); } void @@ -546,7 +649,7 @@ meta_window_resize (MetaWindow *window, int w, int h) { - meta_window_move_resize_internal (window, FALSE, TRUE, -1, -1, w, h); + meta_window_move_resize_internal (window, FALSE, TRUE, FALSE, -1, -1, w, h); } void @@ -554,7 +657,7 @@ meta_window_move (MetaWindow *window, int root_x_nw, int root_y_nw) { - meta_window_move_resize_internal (window, TRUE, FALSE, + meta_window_move_resize_internal (window, TRUE, FALSE, FALSE, root_x_nw, root_y_nw, -1, -1); } @@ -565,11 +668,40 @@ meta_window_move_resize (MetaWindow *window, int w, int h) { - meta_window_move_resize_internal (window, TRUE, TRUE, + meta_window_move_resize_internal (window, TRUE, TRUE, FALSE, root_x_nw, root_y_nw, w, h); } +void +meta_window_queue_move_resize (MetaWindow *window) +{ + /* FIXME actually queue */ + int x, y; + + meta_window_get_position (window, &x, &y); + + meta_window_move_resize (window, x, y, + window->rect.width, window->rect.height); +} + +void +meta_window_get_position (MetaWindow *window, + int *x, + int *y) +{ + if (window->frame) + { + *x = window->frame->rect.x + window->frame->child_x; + *y = window->frame->rect.y + window->frame->child_y; + } + else + { + *x = window->rect.x; + *y = window->rect.y; + } +} + void meta_window_delete (MetaWindow *window, Time timestamp) @@ -832,7 +964,17 @@ meta_window_client_message (MetaWindow *window, return TRUE; } + else if (event->xclient.message_type == + display->atom_wm_change_state) + { + meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", + event->xclient.data.l[0]); + if (event->xclient.data.l[0] == IconicState) + meta_window_minimize (window); + return TRUE; + } + return FALSE; } @@ -844,30 +986,27 @@ process_property_notify (MetaWindow *window, event->atom == window->display->atom_net_wm_name) { update_title (window); - - if (window->frame) - meta_frame_queue_recalc (window->frame); + + meta_window_queue_move_resize (window); } else if (event->atom == XA_WM_NORMAL_HINTS) { update_size_hints (window); /* See if we need to constrain current size */ - meta_window_resize (window, window->rect.width, window->rect.height); + meta_window_queue_move_resize (window); } else if (event->atom == window->display->atom_wm_protocols) { update_protocols (window); - if (window->frame) - meta_frame_queue_recalc (window->frame); + meta_window_queue_move_resize (window); } else if (event->atom == XA_WM_HINTS) { update_wm_hints (window); - if (window->frame) - meta_frame_queue_recalc (window->frame); + meta_window_queue_move_resize (window); } else if (event->atom == window->display->atom_motif_wm_hints) { @@ -878,8 +1017,29 @@ process_property_notify (MetaWindow *window, else meta_window_destroy_frame (window); - if (window->frame) - meta_frame_queue_recalc (window->frame); + meta_window_queue_move_resize (window); + } + else if (event->atom == XA_WM_CLASS) + { + update_wm_class (window); + } + else if (event->atom == XA_WM_TRANSIENT_FOR) + { + update_transient_for (window); + + meta_window_queue_move_resize (window); + } + else if (event->atom == + window->display->atom_wm_window_role) + { + update_role (window); + } + else if (event->atom == + window->display->atom_wm_client_leader || + event->atom == + window->display->atom_sm_client_id) + { + meta_warning ("Broken client changed client leader window or SM client ID\n"); } return TRUE; @@ -891,6 +1051,9 @@ send_configure_notify (MetaWindow *window) XEvent event; /* from twm */ + + meta_verbose ("Sending synthetic ConfigureNotify to %s\n", + window->desc); event.type = ConfigureNotify; event.xconfigure.display = window->display->xdisplay; @@ -929,9 +1092,6 @@ process_configure_request (MetaWindow *window, int border_width) { /* ICCCM 4.1.5 */ - XWindowChanges values; - unsigned int mask; - int client_x, client_y; /* Note that x, y is the corner of the window border, * and width, height is the size of the window inside @@ -948,74 +1108,13 @@ process_configure_request (MetaWindow *window, window->size_hints.y = y; window->size_hints.width = width; window->size_hints.height = height; - - constrain_size (window, - window->size_hints.width, - window->size_hints.height, - &window->size_hints.width, - &window->size_hints.height); - meta_verbose ("Constrained configure request size to %d x %d\n", - window->size_hints.width, window->size_hints.height); + meta_window_move_resize_internal (window, TRUE, TRUE, TRUE, + window->size_hints.x, + window->size_hints.y, + window->size_hints.width, + window->size_hints.height); - if (window->frame) - { - meta_frame_child_configure_request (window->frame); - client_x = window->frame->child_x; - client_y = window->frame->child_y; - meta_verbose ("Will place client window %s inside frame at %d,%d\n", - window->desc, client_x, client_y); - } - else - { - client_x = window->size_hints.x; - client_y = window->size_hints.y; - meta_verbose ("Will place client window %s at root coordinate %d,%d\n", - window->desc, client_x, client_y); - } - - values.border_width = 0; - values.x = client_x; - values.y = client_y; - values.width = window->size_hints.width; - values.height = window->size_hints.height; - - mask = 0; - if (window->border_width != 0) - mask |= CWBorderWidth; - if (values.x != window->rect.x) - mask |= CWX; - if (values.y != window->rect.y) - mask |= CWY; - if (values.width != window->rect.width) - mask |= CWWidth; - if (values.height != window->rect.height) - mask |= CWHeight; - - window->rect.x = values.x; - window->rect.y = values.y; - window->rect.width = values.width; - window->rect.height = values.height; - - meta_error_trap_push (window->display); - XConfigureWindow (window->display->xdisplay, - window->xwindow, - mask, - &values); - meta_error_trap_pop (window->display); - - if (mask & (CWBorderWidth | CWWidth | CWHeight)) - { - /* Resizing, no synthetic ConfigureNotify, third case in 4.1.5 */ - } - else - { - /* Moving but not resizing, second case in 4.1.5, or - * have to send the ConfigureNotify, first case in 4.1.5 - */ - send_configure_notify (window); - } - return TRUE; } @@ -1296,12 +1395,15 @@ update_wm_hints (MetaWindow *window) { window->input = (hints->flags & InputHint) != 0; - window->initially_iconic = (hints->initial_state == IconicState); - - /* FIXME there are a few others there. */ + if (hints->flags & StateHint) + window->initially_iconic = (hints->initial_state == IconicState); - meta_verbose ("Read WM_HINTS input: %d iconic: %d\n", - window->input, window->initially_iconic); + if (hints->flags & WindowGroupHint) + window->xgroup_leader = hints->window_group; + + meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%ld\n", + window->input, window->initially_iconic, + window->xgroup_leader); XFree (hints); } @@ -1452,6 +1554,202 @@ update_mwm_hints (MetaWindow *window) return Success; } +static int +update_wm_class (MetaWindow *window) +{ + XClassHint ch; + + if (window->res_class) + g_free (window->res_class); + if (window->res_name) + g_free (window->res_name); + + window->res_class = NULL; + window->res_name = NULL; + + meta_error_trap_push (window->display); + + ch.res_name = NULL; + ch.res_class = NULL; + + XGetClassHint (window->display->xdisplay, + window->xwindow, + &ch); + + if (ch.res_name) + { + window->res_name = g_strdup (ch.res_name); + XFree (ch.res_name); + } + + if (ch.res_class) + { + window->res_class = g_strdup (ch.res_class); + XFree (ch.res_class); + } + + meta_verbose ("Window %s class: '%s' name: '%s'\n", + window->desc, + window->res_class ? window->res_class : "(null)", + window->res_name ? window->res_name : "(null)"); + + return meta_error_trap_pop (window->display); +} + +static int +read_string_prop (MetaDisplay *display, + Window xwindow, + Atom atom, + char **strp) +{ + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + guchar *str; + int result; + + meta_error_trap_push (display); + str = NULL; + XGetWindowProperty (display->xdisplay, + xwindow, atom, + 0, G_MAXLONG, + False, XA_STRING, &type, &format, &nitems, + &bytes_after, (guchar **)&str); + + result = meta_error_trap_pop (display); + if (result != Success) + return result; + + if (type != XA_STRING) + return -1; /* whatever */ + + *strp = g_strdup (str); + + XFree (str); + + return Success; +} + +static Window +read_client_leader (MetaDisplay *display, + Window xwindow) +{ + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + Window *leader; + int result; + Window retval; + + meta_error_trap_push (display); + leader = NULL; + XGetWindowProperty (display->xdisplay, xwindow, + display->atom_wm_client_leader, + 0, G_MAXLONG, + False, XA_WINDOW, &type, &format, &nitems, + &bytes_after, (guchar **)&leader); + + result = meta_error_trap_pop (display); + if (result != Success) + return None; + + if (type != XA_WINDOW) + return None; + + retval = *leader; + + XFree (leader); + + return retval; +} + +static void +update_sm_hints (MetaWindow *window) +{ + MetaWindow *w; + Window leader; + + window->xclient_leader = None; + window->sm_client_id = NULL; + + /* If not on the current window, we can get the client + * leader from transient parents. If we find a client + * leader, we read the SM_CLIENT_ID from it. + */ + leader = None; + w = window; + while (w != NULL) + { + leader = read_client_leader (window->display, w->xwindow); + + if (leader != None) + break; + + if (w->xtransient_for == None) + break; + + w = meta_display_lookup_x_window (w->display, w->xtransient_for); + + if (w == window) + break; /* Cute, someone thought they'd make a transient_for cycle */ + } + + if (leader) + { + window->xclient_leader = leader; + read_string_prop (window->display, leader, + window->display->atom_sm_client_id, + &window->sm_client_id); + + meta_verbose ("Window %s client leader: 0x%ld SM_CLIENT_ID: '%s'\n", + window->desc, window->xclient_leader, window->sm_client_id); + } + else + meta_verbose ("Didn't find a client leader for %s\n", window->desc); +} + +static int +update_role (MetaWindow *window) +{ + int result; + + if (window->role) + g_free (window->role); + window->role = NULL; + + result = read_string_prop (window->display, window->xwindow, + window->display->atom_wm_window_role, + &window->role); + + meta_verbose ("Updated role of %s to '%s'\n", + window->desc, window->role ? window->role : "(null)"); + + return Success; +} + +static int +update_transient_for (MetaWindow *window) +{ + Window w; + + meta_error_trap_push (window->display); + w = None; + XGetTransientForHint (window->display->xdisplay, + window->xwindow, + &w); + window->xtransient_for = w; + + if (window->xtransient_for != None) + meta_verbose ("Window %s transient for 0x%ld\n", window->desc, + window->xtransient_for); + else + meta_verbose ("Window %s is not transient\n", window->desc); + + return meta_error_trap_pop (window->display); +} + static void constrain_size (MetaWindow *window, int width, int height, @@ -1469,6 +1767,8 @@ constrain_size (MetaWindow *window, int delta; double min_aspect, max_aspect; int minw, minh, maxw, maxh, fullw, fullh; + + /* frame member variables should NEVER be used in here */ #define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) ) @@ -1560,3 +1860,43 @@ constrain_size (MetaWindow *window, *new_height = height; } +static void +constrain_position (MetaWindow *window, + MetaFrameGeometry *fgeom, + int x, + int y, + int *new_x, + int *new_y) +{ + int nw_x, nw_y; + + /* frame member variables should NEVER be used in here, only + * MetaFrameGeometry + */ + + /* find furthest northwest corner */ + nw_x = window->screen->active_workspace->workarea.x; + nw_y = window->screen->active_workspace->workarea.y; + if (window->frame) + { + nw_x += fgeom->left_width; + nw_y += fgeom->top_height; + } + + /* don't allow moving titlebar off the top or left */ + if (x < nw_x) + x = nw_x; + if (y < nw_y) + y = nw_y; + + if (window->maximized) + { + if (x != nw_x) + x = nw_x; + if (y != nw_y) + y = nw_y; + } + + *new_x = x; + *new_y = y; +} diff --git a/src/window.h b/src/window.h index fdce20e3a..7ee063588 100644 --- a/src/window.h +++ b/src/window.h @@ -39,6 +39,18 @@ struct _MetaWindow char *desc; /* used in debug spew */ char *title; + /* NOTE these four are not in UTF-8, we just treat them as random + * binary data + */ + char *res_class; + char *res_name; + char *role; + char *sm_client_id; + + Window xtransient_for; + Window xgroup_leader; + Window xclient_leader; + /* Whether we're maximized */ guint maximized : 1; @@ -127,6 +139,15 @@ void meta_window_move_resize (MetaWindow *window, int root_y_nw, int w, int h); +/* This recalcs the window/frame size, and recalcs the frame + * size/contents as well. + */ +void meta_window_queue_move_resize (MetaWindow *window); + +/* this gets root coords */ +void meta_window_get_position (MetaWindow *window, + int *x, + int *y); void meta_window_delete (MetaWindow *window, Time timestamp); void meta_window_focus (MetaWindow *window,