/* Metacity X managed windows */
/*
* Copyright (C) 2001 Havoc Pennington, Anders Carlsson
*
* 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 <config.h>
#include "window.h"
#include "util.h"
#include "frame.h"
#include "errors.h"
#include "workspace.h"
#include "stack.h"
#include "keybindings.h"
#include "ui.h"
#include "place.h"
#include "session.h"
#include "effects.h"
#include "prefs.h"
#include "resizepopup.h"
#include "xprops.h"
#include <X11/Xatom.h>
typedef enum
{
META_IS_CONFIGURE_REQUEST = 1 << 0,
META_DO_GRAVITY_ADJUST = 1 << 1,
META_USER_MOVE_RESIZE = 1 << 2
} MetaMoveResizeFlags;
typedef enum
{
WIN_HINTS_SKIP_FOCUS = (1<<0), /* "alt-tab" skips this win */
WIN_HINTS_SKIP_WINLIST = (1<<1), /* not in win list */
WIN_HINTS_SKIP_TASKBAR = (1<<2), /* not on taskbar */
WIN_HINTS_GROUP_TRANSIENT = (1<<3), /* ??????? */
WIN_HINTS_FOCUS_ON_CLICK = (1<<4), /* app only accepts focus when clicked */
WIN_HINTS_DO_NOT_COVER = (1<<5) /* attempt to not cover this window */
} GnomeWinHints;
static int destroying_windows_disallowed = 0;
static void constrain_size (MetaWindow *window,
MetaFrameGeometry *fgeom,
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 void update_net_wm_state (MetaWindow *window);
static void 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 void update_role (MetaWindow *window);
static void update_net_wm_type (MetaWindow *window);
static int update_initial_workspace (MetaWindow *window);
static int update_icon_name (MetaWindow *window);
static int update_icon (MetaWindow *window);
static void redraw_icon (MetaWindow *window);
static void update_struts (MetaWindow *window);
static void recalc_window_type (MetaWindow *window);
static void recalc_window_features (MetaWindow *window);
static void recalc_do_not_cover_struts(MetaWindow *window);
static void invalidate_work_areas (MetaWindow *window);
static int set_wm_state (MetaWindow *window,
int state);
static int set_net_wm_state (MetaWindow *window);
static void send_configure_notify (MetaWindow *window);
static gboolean process_property_notify (MetaWindow *window,
XPropertyEvent *event);
static void meta_window_show (MetaWindow *window);
static void meta_window_hide (MetaWindow *window);
static GList* meta_window_get_workspaces (MetaWindow *window);
static gboolean meta_window_get_icon_geometry (MetaWindow *window,
MetaRectangle *rect);
static void adjust_for_gravity (MetaWindow *window,
MetaFrameGeometry *fgeom,
gboolean coords_assume_border,
int x,
int y,
int *xp,
int *yp);
static void meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,
int root_x_nw,
int root_y_nw,
int w,
int h);
void meta_window_move_resize_now (MetaWindow *window);
static char* get_text_property (MetaDisplay *display,
Window xwindow,
Atom atom);
void meta_window_unqueue_calc_showing (MetaWindow *window);
void meta_window_flush_calc_showing (MetaWindow *window);
void meta_window_unqueue_move_resize (MetaWindow *window);
void meta_window_flush_move_resize (MetaWindow *window);
static void meta_window_apply_session_info (MetaWindow *window,
const MetaWindowSessionInfo *info);
static const char*
wm_state_to_string (int state)
{
switch (state)
{
case NormalState:
return "NormalState";
case IconicState:
return "IconicState";
case WithdrawnState:
return "WithdrawnState";
}
return "Unknown";
}
MetaWindow*
meta_window_new (MetaDisplay *display, Window xwindow,
gboolean must_be_viewable)
{
MetaWindow *window;
XWindowAttributes attrs;
GSList *tmp;
MetaWorkspace *space;
gulong existing_wm_state;
char *str;
unsigned long cardinal;
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
if (xwindow == display->no_focus_window)
{
meta_verbose ("Not managing no_focus_window 0x%lx\n",
xwindow);
return NULL;
}
/* Grab server */
meta_display_grab (display);
meta_error_trap_push (display);
XGetWindowAttributes (display->xdisplay,
xwindow, &attrs);
if (meta_error_trap_pop (display))
{
meta_verbose ("Failed to get attributes for window 0x%lx\n",
xwindow);
meta_display_ungrab (display);
return NULL;
}
if (attrs.override_redirect)
{
meta_verbose ("Deciding not to manage override_redirect window 0x%lx\n", xwindow);
meta_display_ungrab (display);
return NULL;
}
meta_verbose ("must_be_viewable = %d attrs.map_state = %d (%s)\n",
must_be_viewable,
attrs.map_state,
(attrs.map_state == IsUnmapped) ?
"IsUnmapped" :
(attrs.map_state == IsViewable) ?
"IsViewable" :
(attrs.map_state == IsUnviewable) ?
"IsUnviewable" :
"(unknown)");
existing_wm_state = WithdrawnState;
if (must_be_viewable && attrs.map_state != IsViewable)
{
/* Only manage if WM_STATE is IconicState or NormalState */
gulong state;
/* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
display->atom_wm_state,
display->atom_wm_state,
&state) &&
(state == IconicState || state == NormalState)))
{
meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
meta_display_ungrab (display);
return NULL;
}
existing_wm_state = state;
meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
wm_state_to_string (existing_wm_state));
}
meta_error_trap_push (display);
XAddToSaveSet (display->xdisplay, xwindow);
XSelectInput (display->xdisplay, xwindow,
PropertyChangeMask |
EnterWindowMask | LeaveWindowMask |
FocusChangeMask);
/* Get rid of any borders */
if (attrs.border_width != 0)
XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
/* Get rid of weird gravities */
if (attrs.win_gravity != NorthWestGravity)
{
XSetWindowAttributes set_attrs;
set_attrs.win_gravity = NorthWestGravity;
XChangeWindowAttributes (display->xdisplay,
xwindow,
CWWinGravity,
&set_attrs);
}
if (meta_error_trap_pop (display) != Success)
{
meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
xwindow);
meta_display_ungrab (display);
return NULL;
}
g_assert (!attrs.override_redirect);
window = g_new (MetaWindow, 1);
window->dialog_pid = -1;
window->dialog_pipe = -1;
window->xwindow = xwindow;
/* this is in window->screen->display, but that's too annoying to
* type
*/
window->display = display;
window->workspaces = NULL;
window->screen = NULL;
tmp = display->screens;
while (tmp != NULL)
{
MetaScreen *scr = tmp->data;
if (scr->xroot == attrs.root)
{
window->screen = tmp->data;
break;
}
tmp = tmp->next;
}
g_assert (window->screen);
/* avoid tons of stack updates */
meta_stack_freeze (window->screen->stack);
/* Remember this rect is the actual window size */
window->rect.x = attrs.x;
window->rect.y = attrs.y;
window->rect.width = attrs.width;
window->rect.height = attrs.height;
window->size_hints.flags = 0;
/* And border width, size_hints are the "request" */
window->border_width = attrs.border_width;
window->size_hints.x = attrs.x;
window->size_hints.y = attrs.y;
window->size_hints.width = attrs.width;
window->size_hints.height = attrs.height;
/* And this is our unmaximized size */
window->saved_rect = window->rect;
window->user_rect = window->rect;
window->depth = attrs.depth;
window->xvisual = attrs.visual;
window->colormap = attrs.colormap;
window->title = NULL;
window->icon_name = NULL;
window->icon = NULL;
window->mini_icon = NULL;
meta_icon_cache_init (&window->icon_cache);
window->wm_hints_pixmap = None;
window->wm_hints_mask = None;
window->desc = g_strdup_printf ("0x%lx", window->xwindow);
window->frame = NULL;
window->has_focus = FALSE;
window->user_has_move_resized = FALSE;
window->maximized = FALSE;
window->fullscreen = FALSE;
window->on_all_workspaces = FALSE;
window->shaded = FALSE;
window->initially_iconic = FALSE;
window->minimized = FALSE;
window->iconic = FALSE;
window->mapped = attrs.map_state != IsUnmapped;
/* if already mapped we don't want to do the placement thing */
window->placed = window->mapped;
if (window->placed)
meta_topic (META_DEBUG_PLACEMENT,
"Not placing window 0x%lx since it's already mapped\n",
xwindow);
window->unmanaging = FALSE;
window->calc_showing_queued = FALSE;
window->move_resize_queued = FALSE;
window->keys_grabbed = FALSE;
window->grab_on_frame = FALSE;
window->all_keys_grabbed = FALSE;
window->withdrawn = FALSE;
window->initial_workspace_set = FALSE;
window->calc_placement = FALSE;
window->unmaps_pending = 0;
window->mwm_decorated = TRUE;
window->mwm_has_close_func = TRUE;
window->mwm_has_minimize_func = TRUE;
window->mwm_has_maximize_func = TRUE;
window->mwm_has_move_func = TRUE;
window->mwm_has_resize_func = TRUE;
window->decorated = TRUE;
window->has_close_func = TRUE;
window->has_minimize_func = TRUE;
window->has_maximize_func = TRUE;
window->has_move_func = TRUE;
window->has_resize_func = TRUE;
window->has_shade_func = TRUE;
window->has_fullscreen_func = TRUE;
window->wm_state_modal = FALSE;
window->wm_state_skip_taskbar = FALSE;
window->wm_state_skip_pager = FALSE;
window->res_class = NULL;
window->res_name = NULL;
window->role = NULL;
window->sm_client_id = NULL;
window->wm_client_machine = NULL;
window->net_wm_pid = -1;
window->xtransient_for = None;
window->xgroup_leader = None;
window->xclient_leader = None;
window->type = META_WINDOW_NORMAL;
window->type_atom = None;
window->has_struts = FALSE;
window->left_strut = 0;
window->right_strut = 0;
window->top_strut = 0;
window->bottom_strut = 0;
window->layer = META_LAYER_NORMAL;
window->stack_op = NULL;
window->initial_workspace = 0; /* not used */
|