This commit is contained in:
rhp 2001-06-09 21:58:30 +00:00
parent c533bc838e
commit 146361b6f5
9 changed files with 716 additions and 315 deletions

View File

@ -55,6 +55,8 @@ metacity_SOURCES= \
main.h \
screen.c \
screen.h \
session.c \
session.h \
theme.c \
theme.h \
uislave.c \

View File

@ -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;
@ -176,6 +184,13 @@ meta_display_open (const char *name)
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;
while (tmp != NULL)
@ -242,6 +257,8 @@ meta_display_close (MetaDisplay *display)
*/
g_hash_table_destroy (display->window_ids);
XDestroyWindow (display->xdisplay, display->leader_window);
meta_event_queue_free (display->events);
XCloseDisplay (display->xdisplay);
g_free (display->name);

View File

@ -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

View File

@ -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;
window = frame->window;
/* 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;
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);
@ -173,19 +191,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;
@ -246,24 +250,13 @@ meta_window_ensure_frame (MetaWindow *window)
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);
frame->rect = window->rect;
frame->child_x = 0;
frame->child_y = 0;
frame->bottom_height = 0;
frame->right_width = 0;
frame->bg_pixel = 0;
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;
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))

View File

@ -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

27
src/session.c Normal file
View File

@ -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"

48
src/session.h Normal file
View File

@ -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

View File

@ -27,17 +27,28 @@
#include <X11/Xatom.h>
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)
@ -156,6 +175,15 @@ meta_window_new (MetaDisplay *display, Window xwindow)
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);
update_size_hints (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)
{
@ -172,10 +204,6 @@ meta_window_new (MetaDisplay *display, Window xwindow)
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,11 +408,9 @@ 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)
{
@ -383,22 +418,9 @@ meta_window_maximize (MetaWindow *window)
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,6 +964,16 @@ 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;
}
@ -845,29 +987,26 @@ process_property_notify (MetaWindow *window,
{
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;
@ -892,6 +1052,9 @@ send_configure_notify (MetaWindow *window)
/* from twm */
meta_verbose ("Sending synthetic ConfigureNotify to %s\n",
window->desc);
event.type = ConfigureNotify;
event.xconfigure.display = window->display->xdisplay;
event.xconfigure.event = window->xwindow;
@ -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
@ -949,72 +1109,11 @@ process_configure_request (MetaWindow *window,
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);
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);
}
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);
return TRUE;
}
@ -1296,12 +1395,15 @@ update_wm_hints (MetaWindow *window)
{
window->input = (hints->flags & InputHint) != 0;
window->initially_iconic = (hints->initial_state == IconicState);
if (hints->flags & StateHint)
window->initially_iconic = (hints->initial_state == IconicState);
/* FIXME there are a few others there. */
if (hints->flags & WindowGroupHint)
window->xgroup_leader = hints->window_group;
meta_verbose ("Read WM_HINTS input: %d iconic: %d\n",
window->input, window->initially_iconic);
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,
@ -1470,6 +1768,8 @@ constrain_size (MetaWindow *window,
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) )
/* Get the allowed size ranges, considering maximized, etc. */
@ -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;
}

View File

@ -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,