/* window object */
/* vim: set sw=2 et: */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Kim Woelders
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2006-2007 Vincent Untz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, see .
*/
#include
#include
#include
#include
#include "window.h"
#include "class-group.h"
#include "util.h"
#include "xutils.h"
#include "private.h"
#include "wnck-enum-types.h"
/**
* SECTION:window
* @short_description: an object representing a window.
* @see_also: #WnckWorkspace, #WnckApplication, #WnckClassGroup
* @stability: Unstable
*
* The #WnckWindow objects are always owned by libwnck and must not be
* referenced or unreferenced.
*/
#define FALLBACK_NAME _("Untitled window")
#define ALL_WORKSPACES ((int) 0xFFFFFFFF)
static GHashTable *window_hash = NULL;
/* Keep 0-7 in sync with the numbers in the WindowState enum. Yeah I'm
* a loser.
*/
#define COMPRESS_STATE(window) \
( ((window)->priv->is_minimized << 0) | \
((window)->priv->is_maximized_horz << 1) | \
((window)->priv->is_maximized_vert << 2) | \
((window)->priv->is_shaded << 3) | \
((window)->priv->skip_pager << 4) | \
((window)->priv->skip_taskbar << 5) | \
((window)->priv->is_sticky << 6) | \
((window)->priv->is_hidden << 7) | \
((window)->priv->is_fullscreen << 8) | \
((window)->priv->demands_attention << 9) | \
((window)->priv->is_urgent << 10)| \
((window)->priv->is_above << 11)| \
((window)->priv->is_below << 12))
struct _WnckWindowPrivate
{
Window xwindow;
WnckScreen *screen;
WnckApplication *app;
WnckClassGroup *class_group;
Window group_leader;
Window transient_for;
int orig_event_mask;
GdkRectangle icon_geometry;
char *name;
char *icon_name;
char *session_id;
char *session_id_utf8;
char *role;
int pid;
int workspace;
gint sort_order;
WnckWindowType wintype;
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
WnckIconCache *icon_cache;
WnckWindowActions actions;
int x;
int y;
int width;
int height;
int left_frame;
int right_frame;
int top_frame;
int bottom_frame;
char *startup_id;
char *res_class;
char *res_name;
/* true if transient_for points to root window,
* not another app window
*/
guint transient_for_root : 1;
/* window state */
guint is_minimized : 1;
guint is_maximized_horz : 1;
guint is_maximized_vert : 1;
guint is_shaded : 1;
guint is_above : 1;
guint is_below : 1;
guint skip_pager : 1;
guint skip_taskbar : 1;
guint is_sticky : 1;
guint is_hidden : 1;
guint is_fullscreen : 1;
guint demands_attention : 1;
guint is_urgent : 1;
time_t needs_attention_time;
/* _NET_WM_STATE_HIDDEN doesn't map directly into an
* externally-visible state (it determines the WM_STATE
* interpretation)
*/
guint net_wm_state_hidden : 1;
guint wm_state_iconic : 1;
/* idle handler for updates */
guint update_handler;
/* if you add flags, be sure to set them
* when we create the window so we get an initial update
*/
guint need_update_name : 1;
guint need_update_state : 1;
guint need_update_wm_state : 1;
guint need_update_icon_name : 1;
guint need_update_workspace : 1;
guint need_update_actions : 1;
guint need_update_wintype : 1;
guint need_update_transient_for : 1;
guint need_update_startup_id : 1;
guint need_update_wmclass : 1;
guint need_update_wmhints : 1;
guint need_update_frame_extents : 1;
guint need_update_role : 1;
guint need_emit_name_changed : 1;
guint need_emit_icon_changed : 1;
guint need_emit_class_changed : 1;
guint need_emit_role_changed : 1;
guint need_emit_type_changed : 1;
};
G_DEFINE_TYPE (WnckWindow, wnck_window, G_TYPE_OBJECT);
#define WNCK_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), WNCK_TYPE_WINDOW, WnckWindowPrivate))
enum {
NAME_CHANGED,
STATE_CHANGED,
WORKSPACE_CHANGED,
ICON_CHANGED,
ACTIONS_CHANGED,
GEOMETRY_CHANGED,
CLASS_CHANGED,
ROLE_CHANGED,
TYPE_CHANGED,
LAST_SIGNAL
};
static void wnck_window_finalize (GObject *object);
static void emit_name_changed (WnckWindow *window);
static void emit_state_changed (WnckWindow *window,
WnckWindowState changed_mask,
WnckWindowState new_state);
static void emit_workspace_changed (WnckWindow *window);
static void emit_icon_changed (WnckWindow *window);
static void emit_actions_changed (WnckWindow *window,
WnckWindowActions changed_mask,
WnckWindowActions new_actions);
static void emit_geometry_changed (WnckWindow *window);
static void emit_class_changed (WnckWindow *window);
static void emit_role_changed (WnckWindow *window);
static void emit_type_changed (WnckWindow *window);
static void update_name (WnckWindow *window);
static void update_state (WnckWindow *window);
static void update_wm_state (WnckWindow *window);
static void update_icon_name (WnckWindow *window);
static void update_workspace (WnckWindow *window);
static void update_actions (WnckWindow *window);
static void update_wintype (WnckWindow *window);
static void update_transient_for (WnckWindow *window);
static void update_startup_id (WnckWindow *window);
static void update_wmclass (WnckWindow *window);
static void update_frame_extents (WnckWindow *window);
static void update_role (WnckWindow *window);
static void unqueue_update (WnckWindow *window);
static void queue_update (WnckWindow *window);
static void force_update_now (WnckWindow *window);
static WnckWindow* find_last_transient_for (GList *windows,
Window xwindow);
static guint signals[LAST_SIGNAL] = { 0 };
void
_wnck_window_shutdown_all (void)
{
if (window_hash != NULL)
{
g_hash_table_destroy (window_hash);
window_hash = NULL;
}
}
static void
wnck_window_init (WnckWindow *window)
{
window->priv = WNCK_WINDOW_GET_PRIVATE (window);
window->priv->icon_cache = _wnck_icon_cache_new ();
window->priv->icon_geometry.width = -1; /* invalid cached value */
window->priv->workspace = -1;
window->priv->sort_order = G_MAXINT;
/* FIXME: should we have an invalid window type for this? */
window->priv->wintype = WNCK_WINDOW_NORMAL;
}
static void
wnck_window_class_init (WnckWindowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (WnckWindowPrivate));
object_class->finalize = wnck_window_finalize;
/**
* WnckWindow::name-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the name of @window changes.
*/
signals[NAME_CHANGED] =
g_signal_new ("name_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, name_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::state-changed:
* @window: the #WnckWindow which emitted the signal.
* @changed_mask: the bitmask containing bits set for all states of @window
* that have changed.
* @new_state: the new state of @window.
*
* Emitted when the state of @window changes. This can happen when @window is
* (un)minimized, (un)maximized, (un)sticked, (un)shaded, (un)made above,
* (un)made below, (un)set fullscreen, when it needs attention, etc. See
* #WnckWindowState for the complete list of states that might have changed.
*/
signals[STATE_CHANGED] =
g_signal_new ("state_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, state_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 2,
WNCK_TYPE_WINDOW_STATE, WNCK_TYPE_WINDOW_STATE);
/**
* WnckWindow::workspace-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the current workspace of @window changes, or if @window has
* been pinned or unpinned.
*/
signals[WORKSPACE_CHANGED] =
g_signal_new ("workspace_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, workspace_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::icon-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the icon of @window changes.
*/
signals[ICON_CHANGED] =
g_signal_new ("icon_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, icon_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::actions-changed:
* @window: the #WnckWindow which emitted the signal.
* @changed_mask: the bitmask containing bits set for all actions
* availabilities for @window that have changed.
* @new_state: the new actions availabilities for @window.
*
* Emitted when the actions availabilities for @window change.
*/
signals[ACTIONS_CHANGED] =
g_signal_new ("actions_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, actions_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 2,
WNCK_TYPE_WINDOW_ACTIONS,
WNCK_TYPE_WINDOW_ACTIONS);
/**
* WnckWindow::geometry-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the geometry of @window changes.
*/
signals[GEOMETRY_CHANGED] =
g_signal_new ("geometry_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, geometry_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::class-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the class name or instance name of @window changes.
*/
signals[CLASS_CHANGED] =
g_signal_new ("class_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, class_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::role-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the role of @window changes.
*/
signals[ROLE_CHANGED] =
g_signal_new ("role_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, role_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* WnckWindow::type-changed:
* @window: the #WnckWindow which emitted the signal.
*
* Emitted when the EWMH type hint of the window changes.
*
* Since: 3.20
*/
signals[TYPE_CHANGED] =
g_signal_new ("type_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (WnckWindowClass, type_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
wnck_window_finalize (GObject *object)
{
WnckWindow *window;
window = WNCK_WINDOW (object);
_wnck_select_input (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
window->priv->orig_event_mask,
FALSE);
unqueue_update (window);
if (window->priv->app)
g_object_unref (G_OBJECT (window->priv->app));
window->priv->app = NULL;
if (window->priv->class_group)
g_object_unref (G_OBJECT (window->priv->class_group));
window->priv->class_group = NULL;
g_free (window->priv->name);
window->priv->name = NULL;
g_free (window->priv->icon_name);
window->priv->icon_name = NULL;
g_free (window->priv->session_id);
window->priv->session_id = NULL;
g_free (window->priv->session_id_utf8);
window->priv->session_id_utf8 = NULL;
if (window->priv->icon)
g_object_unref (G_OBJECT (window->priv->icon));
window->priv->icon = NULL;
if (window->priv->mini_icon)
g_object_unref (G_OBJECT (window->priv->mini_icon));
window->priv->mini_icon = NULL;
_wnck_icon_cache_free (window->priv->icon_cache);
window->priv->icon_cache = NULL;
g_free (window->priv->startup_id);
window->priv->startup_id = NULL;
g_free (window->priv->res_class);
window->priv->res_class = NULL;
g_free (window->priv->res_name);
window->priv->res_name = NULL;
window->priv->xwindow = None;
G_OBJECT_CLASS (wnck_window_parent_class)->finalize (object);
}
/**
* wnck_window_get:
* @xwindow: an X window ID.
*
* Gets a preexisting #WnckWindow for the X window @xwindow. This will not
* create a #WnckWindow if none exists. The function is robust against bogus
* window IDs.
*
* Return value: (transfer none): the #WnckWindow for @xwindow. The returned
* #WnckWindow is owned by libwnck and must not be referenced or unreferenced.
**/
WnckWindow*
wnck_window_get (gulong xwindow)
{
if (window_hash == NULL)
return NULL;
else
return g_hash_table_lookup (window_hash, &xwindow);
}
/**
* wnck_window_get_screen:
* @window: a #WnckWindow.
*
* Gets the #WnckScreen @window is on.
*
* Return value: (transfer none): the #WnckScreen @window is on. The returned
* #WnckScreen is owned by libwnck and must not be referenced or unreferenced.
**/
WnckScreen*
wnck_window_get_screen (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->screen;
}
WnckWindow*
_wnck_window_create (Window xwindow,
WnckScreen *screen,
gint sort_order)
{
WnckWindow *window;
Screen *xscreen;
if (window_hash == NULL)
window_hash = g_hash_table_new_full (_wnck_xid_hash, _wnck_xid_equal,
NULL, g_object_unref);
g_return_val_if_fail (g_hash_table_lookup (window_hash, &xwindow) == NULL,
NULL);
xscreen = WNCK_SCREEN_XSCREEN (screen);
window = g_object_new (WNCK_TYPE_WINDOW, NULL);
window->priv->xwindow = xwindow;
window->priv->screen = screen;
g_hash_table_insert (window_hash, &window->priv->xwindow, window);
/* Hash now owns one ref, caller gets none */
/* Note that xwindow may correspond to a WnckApplication's xwindow,
* that's why we select the union of the mask we want for Application
* and the one we want for window
*/
window->priv->orig_event_mask =_wnck_select_input (xscreen,
window->priv->xwindow,
WNCK_APP_WINDOW_EVENT_MASK,
TRUE);
/* Default the group leader to the window itself; it is set in
* update_wmhints() if a different group leader is specified.
*/
window->priv->group_leader = window->priv->xwindow;
window->priv->session_id =
_wnck_get_session_id (xscreen, window->priv->xwindow);
window->priv->pid =
_wnck_get_pid (xscreen, window->priv->xwindow);
window->priv->x = 0;
window->priv->y = 0;
window->priv->width = 0;
window->priv->height = 0;
_wnck_get_window_geometry (xscreen,
xwindow,
&window->priv->x,
&window->priv->y,
&window->priv->width,
&window->priv->height);
window->priv->sort_order = sort_order;
window->priv->need_update_name = TRUE;
window->priv->need_update_state = TRUE;
window->priv->need_update_icon_name = TRUE;
window->priv->need_update_wm_state = TRUE;
window->priv->need_update_workspace = TRUE;
window->priv->need_update_actions = TRUE;
window->priv->need_update_wintype = TRUE;
window->priv->need_update_transient_for = TRUE;
window->priv->need_update_startup_id = TRUE;
window->priv->need_update_wmclass = TRUE;
window->priv->need_update_wmhints = TRUE;
window->priv->need_update_frame_extents = TRUE;
window->priv->need_update_role = TRUE;
window->priv->need_emit_name_changed = FALSE;
window->priv->need_emit_icon_changed = FALSE;
window->priv->need_emit_class_changed = FALSE;
window->priv->need_emit_role_changed = FALSE;
window->priv->need_emit_type_changed = FALSE;
force_update_now (window);
return window;
}
void
_wnck_window_destroy (WnckWindow *window)
{
Window xwindow = window->priv->xwindow;
g_return_if_fail (WNCK_IS_WINDOW (window));
g_return_if_fail (wnck_window_get (xwindow) == window);
g_hash_table_remove (window_hash, &xwindow);
/* Removing from hash also removes the only ref WnckWindow had */
g_return_if_fail (wnck_window_get (xwindow) == NULL);
}
static Display *
_wnck_window_get_display (WnckWindow *window)
{
return DisplayOfScreen (WNCK_SCREEN_XSCREEN (window->priv->screen));
}
/**
* wnck_window_has_name:
* @window: a #WnckWindow.
*
* Checks whether or not @window has a name. wnck_window_get_name()
* will always return some value, even if @window has no name set;
* wnck_window_has_name() can be used to tell if that name is
* real or not.
*
* For icons titles, use wnck_window_has_icon_name() instead.
*
* Return value: %TRUE if wnck_window_get_name() returns @window's
* name, %FALSE if it returns a fallback name.
*
* Since: 2.16
**/
gboolean
wnck_window_has_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->name != NULL;
}
/**
* wnck_window_get_name:
* @window: a #WnckWindow.
*
* Gets the name of @window, as it should be displayed in a pager
* or tasklist. Always returns some value, even if @window has no name
* set; use wnck_window_has_name() if you need to know whether the returned
* name is "real" or not.
*
* For icons titles, use wnck_window_get_icon_name() instead.
*
* Return value: the name of @window, or a fallback name if no name is
* available.
**/
const char*
wnck_window_get_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (window->priv->name)
return window->priv->name;
else
return FALLBACK_NAME;
}
/**
* wnck_window_has_icon_name:
* @window: a #WnckWindow
*
* Checks whether or not @window has an icon name.
* wnck_window_get_icon_name() will always return some value, even if
* @window has no icon name set; wnck_window_has_icon_name() can
* be used to tell if that icon name is real or not.
*
* (Note that if wnck_window_has_icon_name() returns %FALSE, but
* wnck_window_has_name() returns %TRUE, then the name returned by
* wnck_window_get_icon_name() is @window's name. Only when both
* methods return %FALSE does wnck_window_get_icon_name() return a
* generic fallback name.)
*
* Return value: %TRUE if wnck_window_get_icon_name() returns
* @window's icon name, %FALSE if it returns a fallback name.
*
* Since: 2.16
**/
gboolean
wnck_window_has_icon_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->icon_name != NULL;
}
/**
* wnck_window_get_icon_name:
* @window: a #WnckWindow
*
* Gets the icon name of @window, as it should be displayed for an icon
* (minimized state). Always returns some value, even if @window has no icon
* name set; use wnck_window_has_icon_name() if you need to know whether the
* returned icon name is "real" or not.
*
* Contrast with wnck_window_get_name(), which returns @window's
* title, not its icon title.
*
* Return value: the icon name of @window, or a fallback icon name if no icon
* name is available.
**/
const char*
wnck_window_get_icon_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (window->priv->icon_name)
return window->priv->icon_name;
else if (window->priv->name)
return window->priv->name;
else
return FALLBACK_NAME;
}
char *
_wnck_window_get_name_for_display (WnckWindow *window,
gboolean use_icon_name,
gboolean use_state_decorations)
{
const char *name;
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (use_icon_name && wnck_window_has_icon_name (window))
name = wnck_window_get_icon_name (window);
else
name = wnck_window_get_name (window);
if (use_state_decorations)
{
if (window->priv->is_shaded)
return g_strdup_printf ("=%s=", name);
else if (window->priv->is_minimized)
return g_strdup_printf ("[%s]", name);
else
return g_strdup (name);
}
else
return g_strdup (name);
}
/**
* wnck_window_get_application:
* @window: a #WnckWindow.
*
* Gets the #WnckApplication to which @window belongs.
*
* Return value: (transfer none): the #WnckApplication to which @window belongs.
* The returned #WnckApplication is owned by libwnck and must not be referenced
* or unreferenced.
**/
WnckApplication*
wnck_window_get_application (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->app;
}
/**
* wnck_window_get_transient:
* @window: a #WnckWindow.
*
* Gets the #WnckWindow for which @window is transient.
*
* Return value: (transfer none): the #WnckWindow for which @window is
* transient, or %NULL if @window is not transient for any #WnckWindow.
* The returned #WnckWindow is owned by libwnck and must not be referenced or
* unreferenced.
*
* Since: 2.12
**/
WnckWindow*
wnck_window_get_transient (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return wnck_window_get (window->priv->transient_for);
}
/**
* wnck_window_get_group_leader:
* @window: a #WnckWindow.
*
* Gets the group leader of the group of windows to which @window belongs.
*
* Return value: the group leader of the group of windows to which @window
* belongs, or the X window ID of @window if @window does not belong to any
* group.
**/
gulong
wnck_window_get_group_leader (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), None);
return window->priv->group_leader;
}
/**
* wnck_window_get_xid:
* @window: a #WnckWindow.
*
* Gets the X window ID of @window.
*
* Return value: the X window ID of @window.
**/
gulong
wnck_window_get_xid (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), None);
return window->priv->xwindow;
}
/**
* wnck_window_get_class_group:
* @window: a #WnckWindow.
*
* Gets the #WnckClassGroup to which @window belongs.
*
* Return value: (transfer none): the #WnckClassGroup to which @window belongs.
* The returned #WnckClassGroup is owned by libwnck and must not be referenced
* or unreferenced.
*
* Since: 2.2
**/
WnckClassGroup *
wnck_window_get_class_group (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->class_group;
}
/**
* wnck_window_get_session_id:
* @window: a #WnckWindow.
*
* Gets the session ID for @window in Latin-1 encoding.
* NOTE: this is invalid UTF-8. You can't display this
* string in a GTK+ widget without converting to UTF-8.
* See wnck_window_get_session_id_utf8().
*
* Return value: the session ID for @window in Latin-1, or %NULL if @window has
* no session ID.
**/
const char*
wnck_window_get_session_id (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->session_id;
}
/**
* wnck_window_get_session_id_utf8:
* @window: a #WnckWindow.
*
* Gets the session ID for @window in UTF-8 encoding.
* The session ID should be in Latin-1 encoding, so the conversion should work,
* but a broken client could set a session ID that might not be convertable to
* UTF-8.
*
* Return value: the session ID for @window in UTF-8, or %NULL if @window has
* no session ID.
**/
const char*
wnck_window_get_session_id_utf8 (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (window->priv->session_id_utf8 == NULL &&
window->priv->session_id != NULL)
{
GString *str;
char *p;
str = g_string_new ("");
p = window->priv->session_id;
while (*p)
{
g_string_append_unichar (str, g_utf8_get_char (p));
p = g_utf8_next_char (p);
}
window->priv->session_id_utf8 = g_string_free (str, FALSE);
}
return window->priv->session_id_utf8;
}
/**
* wnck_window_get_role:
* @window: a #WnckWindow.
*
* Gets the role for @window.
* The role uniquely identifies a window among all windows that have the same
* client leader window.
*
* Return value: role for @window, or %NULL if @window has no role.
**/
const char*
wnck_window_get_role (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->role;
}
/**
* wnck_window_get_pid:
* @window: a #WnckWindow.
*
* Gets the process ID of @window.
*
* Return value: the process ID of @window, or 0 if none is available.
**/
int
wnck_window_get_pid (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
return window->priv->pid;
}
/**
* wnck_window_get_sort_order:
* @window: a #WnckWindow.
*
* Gets the sort order of @window, used for ordering of @window in
* #WnckSelector and #WnckTasklist. The sort order is an internal state in
* libwnck. The initial value is defined when the window is created.
*
* Return value: the sort order of @window, or G_MAXINT if none is available.
*
* Since: 2.10
**/
gint
wnck_window_get_sort_order (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), G_MAXINT);
return window->priv->sort_order;
}
/**
* wnck_window_set_sort_order:
* @window: a #WnckWindow.
* @order: new sort order for @window.
*
* Sets the sort order of @window. The sort order is used for ordering of
* @window in #WnckSelector and #WnckTasklist.
*
* Since: 2.20
**/
void wnck_window_set_sort_order (WnckWindow *window,
gint order)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
window->priv->sort_order = order;
return;
}
/**
* wnck_window_get_window_type:
* @window: a #WnckWindow.
*
* Gets the semantic type of @window.
*
* Return value: the semantic type of @window.
**/
WnckWindowType
wnck_window_get_window_type (WnckWindow *window)
{
/* FIXME: should we have an invalid window type for this? */
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
return window->priv->wintype;
}
/**
* wnck_window_set_window_type:
* @window: a #WnckWindow.
* @wintype: a semantic type.
*
* Sets the semantic type of @window to @wintype.
*
* Since: 2.12
**/
void
wnck_window_set_window_type (WnckWindow *window, WnckWindowType wintype)
{
Atom atom;
Display *display;
g_return_if_fail (WNCK_IS_WINDOW (window));
switch (wintype) {
case WNCK_WINDOW_NORMAL:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_NORMAL");
break;
case WNCK_WINDOW_DESKTOP:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DESKTOP");
break;
case WNCK_WINDOW_DOCK:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DOCK");
break;
case WNCK_WINDOW_DIALOG:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DIALOG");
break;
case WNCK_WINDOW_TOOLBAR:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_TOOLBAR");
break;
case WNCK_WINDOW_MENU:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_MENU");
break;
case WNCK_WINDOW_UTILITY:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_UTILITY");
break;
case WNCK_WINDOW_SPLASHSCREEN:
atom = _wnck_atom_get ("_NET_WM_WINDOW_TYPE_SPLASH");
break;
default:
return;
}
display = _wnck_window_get_display (window);
_wnck_error_trap_push (display);
XChangeProperty (display,
window->priv->xwindow,
_wnck_atom_get ("_NET_WM_WINDOW_TYPE"),
XA_ATOM, 32, PropModeReplace,
(guchar *)&atom, 1);
_wnck_error_trap_pop (display);
emit_type_changed (window);
}
/**
* wnck_window_is_minimized:
* @window: a #WnckWindow.
*
* Gets whether @window is minimized. Minimization state may change anytime
* a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is minimized, %FALSE otherwise.
**/
gboolean
wnck_window_is_minimized (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_minimized;
}
/**
* wnck_window_needs_attention:
* @window: a #WnckWindow.
*
* Gets whether @window needs attention. This state may change anytime
* a #WnckWindow::state-changed signal gets emitted.
*
* This state depends on flags such as the demands_attention and is_urgent
* hints.
*
* Return value: %TRUE if @window needs attention, %FALSE otherwise.
*
* Since: 2.12
**/
gboolean
wnck_window_needs_attention (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->demands_attention || window->priv->is_urgent;
}
time_t
_wnck_window_get_needs_attention_time (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
return window->priv->needs_attention_time;
}
/* Return whether the transient of @window needs attention */
static WnckWindow *
transient_needs_attention (WnckWindow *window)
{
GList *windows;
WnckWindow *transient;
if (!WNCK_IS_WINDOW (window))
return NULL;
windows = wnck_screen_get_windows_stacked (window->priv->screen);
transient = window;
while ((transient = find_last_transient_for (windows, transient->priv->xwindow)))
{
/* catch transient cycles */
if (transient == window)
return NULL;
if (wnck_window_needs_attention (transient))
return transient;
}
return FALSE;
}
time_t
_wnck_window_or_transient_get_needs_attention_time (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
if (_wnck_window_get_needs_attention_time (window) == 0)
{
WnckWindow *transient;
transient = transient_needs_attention (window);
if (transient)
return _wnck_window_get_needs_attention_time (transient);
else
return 0;
}
else
return _wnck_window_get_needs_attention_time (window);
}
/**
* wnck_window_or_transient_needs_attention:
* @window: a #WnckWindow.
*
* Gets whether @window or one of its transients needs attention. This state
* may change anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window or one of its transients needs attention,
* %FALSE otherwise.
*
* Since: 2.12
**/
gboolean
wnck_window_or_transient_needs_attention (WnckWindow *window)
{
return wnck_window_needs_attention (window) ||
transient_needs_attention (window) != NULL;
}
/**
* wnck_window_is_maximized_horizontally:
* @window: a #WnckWindow.
*
* Gets whether @window is maximized horizontally. Horizontal maximization
* state may change anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is maximized horizontally, %FALSE otherwise.
**/
gboolean
wnck_window_is_maximized_horizontally (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_maximized_horz;
}
/**
* wnck_window_is_maximized_vertically:
* @window: a #WnckWindow.
*
* Gets whether @window is maximized vertically. vertiVal maximization
* state may change anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is maximized vertically, %FALSE otherwise.
**/
gboolean
wnck_window_is_maximized_vertically (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_maximized_vert;
}
const char*
_wnck_window_get_startup_id (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (window->priv->startup_id == NULL &&
window->priv->group_leader != None)
{
WnckApplication *app;
/* Fall back to group leader property */
app = wnck_application_get (window->priv->group_leader);
if (app != NULL)
return wnck_application_get_startup_id (app);
else
return NULL;
}
return window->priv->startup_id;
}
/**
* wnck_window_get_class_group_name:
* @window: a #WnckWindow.
*
* Gets the class group name from the WM_CLASS Property
* for @window.
*
* The class group name is also the identifier name of the #WnckClassGroup to
* which @window belongs.
*
* Return value: the class group name for @window, or %NULL if @window belongs
* to no class group.
**/
const char*
wnck_window_get_class_group_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->res_class;
}
/**
* wnck_window_get_class_instance_name:
* @window: a #WnckWindow.
*
* Gets the class instance name from the WM_CLASS Property
* for @window.
*
* The class instance name allows to differentiate windows belonging to the
* same class group, so that they can use different resources.
*
* Return value: the class instance name for @window, or %NULL if @window has
* no class instance.
**/
const char*
wnck_window_get_class_instance_name (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
return window->priv->res_name;
}
/**
* wnck_window_is_maximized:
* @window: a #WnckWindow.
*
* Gets whether @window is maximized. Maximization state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* As for GDK, "maximized" means both vertically and horizontally. If @window
* is maximized in only one direction, then @window is not considered
* maximized.
*
* Return value: %TRUE if @window is maximized in both directions, %FALSE
* otherwise.
**/
gboolean
wnck_window_is_maximized (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return
window->priv->is_maximized_horz &&
window->priv->is_maximized_vert;
}
/**
* wnck_window_is_shaded:
* @window: a #WnckWindow.
*
* Gets whether @window is shaded. Shade state may change anytime
* a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is shaded, %FALSE otherwise.
**/
gboolean
wnck_window_is_shaded (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_shaded;
}
/**
* wnck_window_is_above:
* @window: a #WnckWindow.
*
* Gets whether @window is above other windows. This state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* See wnck_window_make_above() for more details on this state.
*
* Return value: %TRUE if @window is above other windows, %FALSE otherwise.
*
* Since: 2.14
**/
gboolean
wnck_window_is_above (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_above;
}
/**
* wnck_window_is_below:
* @window: a #WnckWindow.
*
* Gets whether @window is below other windows. This state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* See wnck_window_make_below() for more details on this state.
*
* Return value: %TRUE if @window is below other windows, %FALSE otherwise.
*
* Since: 2.20
**/
gboolean
wnck_window_is_below (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_below;
}
/**
* wnck_window_is_skip_pager:
* @window: a #WnckWindow.
*
* Gets whether @window is included on pagers. This state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is included on pagers, %FALSE otherwise.
**/
gboolean
wnck_window_is_skip_pager (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->skip_pager;
}
/**
* wnck_window_set_skip_pager:
* @window: a #WnckWindow.
* @skip: whether @window should be included on pagers.
*
* Asks the window manager to make @window included or not included on pagers.
**/
void
wnck_window_set_skip_pager (WnckWindow *window,
gboolean skip)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
skip,
_wnck_atom_get ("_NET_WM_STATE_SKIP_PAGER"),
0);
}
/**
* wnck_window_is_skip_tasklist:
* @window: a #WnckWindow.
*
* Gets whether @window is included on tasklists. This state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is included on tasklists, %FALSE otherwise.
**/
gboolean
wnck_window_is_skip_tasklist (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->skip_taskbar;
}
/**
* wnck_window_is_fullscreen:
* @window: a #WnckWindow.
*
* Gets whether @window is fullscreen. Fullscreen state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* Return value: %TRUE if @window is fullscreen, %FALSE otherwise.
*
* Since: 2.8
**/
gboolean
wnck_window_is_fullscreen (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_fullscreen;
}
/**
* wnck_window_set_skip_tasklist:
* @window: a #WnckWindow.
* @skip: whether @window should be included on tasklists.
*
* Asks the window manager to make @window included or not included on
* tasklists.
**/
void
wnck_window_set_skip_tasklist (WnckWindow *window,
gboolean skip)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
skip,
_wnck_atom_get ("_NET_WM_STATE_SKIP_TASKBAR"),
0);
}
/**
* wnck_window_set_fullscreen:
* @window: a #WnckWindow.
* @fullscreen: whether to make @window fullscreen.
*
* Asks the window manager to set the fullscreen state of @window according to
* @fullscreen.
*
* Since: 2.8
**/
void
wnck_window_set_fullscreen (WnckWindow *window,
gboolean fullscreen)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
fullscreen,
_wnck_atom_get ("_NET_WM_STATE_FULLSCREEN"),
0);
}
/**
* wnck_window_is_sticky:
* @window: a #WnckWindow.
*
* Gets whether @window is sticky. Sticky state may change
* anytime a #WnckWindow::state-changed signal gets emitted.
*
* Sticky here means "stuck to the glass", i.e. does not scroll with the
* viewport. In GDK/GTK+ (e.g. gdk_window_stick()/gtk_window_stick()), sticky
* means "stuck to the glass" and also that the window is
* on all workspaces. But here it only means the viewport aspect of it.
*
* Return value: %TRUE if @window is "stuck to the glass", %FALSE otherwise.
**/
gboolean
wnck_window_is_sticky (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->is_sticky;
}
/**
* wnck_window_close:
* @window: a #WnckWindow.
* @timestamp: the X server timestamp of the user interaction event that caused
* this call to occur.
*
* Closes @window.
*
* This function existed before 2.6, but the @timestamp argument was missing
* in earlier versions.
*
* Since: 2.6
**/
void
wnck_window_close (WnckWindow *window,
guint32 timestamp)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_close (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow, timestamp);
}
/**
* wnck_window_minimize:
* @window: a #WnckWindow.
*
* Minimizes @window.
**/
void
wnck_window_minimize (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_iconify (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
}
/**
* wnck_window_unminimize:
* @window: a #WnckWindow.
* @timestamp: the X server timestamp of the user interaction event that caused
* this call to occur.
*
* Unminimizes @window by activating it or one of its transients. See
* wnck_window_activate_transient() for details on how the activation is done.
**/
void
wnck_window_unminimize (WnckWindow *window,
guint32 timestamp)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
wnck_window_activate_transient (window, timestamp);
}
/**
* wnck_window_maximize:
* @window: a #WnckWindow.
*
* Asks the window manager to maximize @window.
**/
void
wnck_window_maximize (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_VERT"),
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_HORZ"));
}
/**
* wnck_window_unmaximize:
* @window: a #WnckWindow.
*
* Asks the window manager to unmaximize @window.
**/
void
wnck_window_unmaximize (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_VERT"),
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_HORZ"));
}
/**
* wnck_window_maximize_horizontally:
* @window: a #WnckWindow.
*
* Asks the window manager to maximize horizontally @window.
**/
void
wnck_window_maximize_horizontally (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_HORZ"),
0);
}
/**
* wnck_window_unmaximize_horizontally:
* @window: a #WnckWindow.
*
* Asks the window manager to unmaximize horizontally @window.
**/
void
wnck_window_unmaximize_horizontally (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_HORZ"),
0);
}
/**
* wnck_window_maximize_vertically:
* @window: a #WnckWindow.
*
* Asks the window manager to maximize vertically @window.
**/
void
wnck_window_maximize_vertically (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_VERT"),
0);
}
/**
* wnck_window_unmaximize_vertically:
* @window: a #WnckWindow.
*
* Asks the window manager to unmaximize vertically @window.
**/
void
wnck_window_unmaximize_vertically (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_VERT"),
0);
}
/**
* wnck_window_shade:
* @window: a #WnckWindow.
*
* Asks the window manager to shade @window.
**/
void
wnck_window_shade (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_SHADED"),
0);
}
/**
* wnck_window_unshade:
* @window: a #WnckWindow.
*
* Asks the window manager to unshade @window.
**/
void
wnck_window_unshade (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_SHADED"),
0);
}
/**
* wnck_window_make_above:
* @window: a #WnckWindow.
*
* Asks the window manager to put @window on top of most windows (@window will
* not be on top of focused fullscreen windows, of other windows with this
* setting and of dock windows).
*
* Since: 2.14
**/
void
wnck_window_make_above (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_ABOVE"),
0);
}
/**
* wnck_window_unmake_above:
* @window: a #WnckWindow.
*
* Asks the window manager to not put @window on top of most windows, and to
* put it again in the stack with other windows.
*
* Since: 2.14
**/
void
wnck_window_unmake_above (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_ABOVE"),
0);
}
/**
* wnck_window_make_below:
* @window: a #WnckWindow.
*
* Asks the window manager to put @window below most windows.
*
* Since: 2.20
**/
void
wnck_window_make_below (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_BELOW"),
0);
}
/**
* wnck_window_unmake_below:
* @window: a #WnckWindow.
*
* Asks the window manager to not put @window below most windows, and to
* put it again in the stack with other windows.
*
* Since: 2.20
**/
void
wnck_window_unmake_below (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_BELOW"),
0);
}
/**
* wnck_window_stick:
* @window: a #WnckWindow.
*
* Asks the window manager to keep the @window's position fixed on the
* screen, even when the workspace or viewport scrolls.
**/
void
wnck_window_stick (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
TRUE,
_wnck_atom_get ("_NET_WM_STATE_STICKY"),
0);
}
/**
* wnck_window_unstick:
* @window: a #WnckWindow.
*
* Asks the window manager to not have @window's position fixed on the
* screen when the workspace or viewport scrolls.
**/
void
wnck_window_unstick (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
FALSE,
_wnck_atom_get ("_NET_WM_STATE_STICKY"),
0);
}
/**
* wnck_window_keyboard_move:
* @window: a #WnckWindow.
*
* Asks the window manager to start moving @window via the keyboard.
**/
void
wnck_window_keyboard_move (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_keyboard_move (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
}
/**
* wnck_window_keyboard_size:
* @window: a #WnckWindow.
*
* Asks the window manager to start resizing @window via the keyboard.
**/
void
wnck_window_keyboard_size (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_keyboard_size (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
}
/**
* wnck_window_get_workspace:
* @window: a #WnckWindow.
*
* Gets the current workspace @window is on. If the window is pinned (on all
* workspaces), or not on any workspaces, %NULL may be returned.
*
* Return value: (transfer none): the single current workspace @window is on, or
* %NULL. The returned #WnckWorkspace is owned by libwnck and must not be
* referenced or unreferenced.
**/
WnckWorkspace*
wnck_window_get_workspace (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
if (window->priv->workspace == ALL_WORKSPACES)
return NULL;
else
return wnck_screen_get_workspace (window->priv->screen, window->priv->workspace);
}
/**
* wnck_window_move_to_workspace:
* @window: a #WnckWindow.
* @space: a #WnckWorkspace.
*
* Asks the window manager to move @window to @space. If @window was pinned, it
* will also result in @window being visible only on @space.
**/
void
wnck_window_move_to_workspace (WnckWindow *window,
WnckWorkspace *space)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
g_return_if_fail (WNCK_IS_WORKSPACE (space));
_wnck_change_workspace (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
wnck_workspace_get_number (space));
}
/**
* wnck_window_is_pinned:
* @window: a #WnckWindow.
*
* Gets whether @window is on all workspace. Pinned state may change
* anytime a #WnckWindow::workspace-changed signal gets emitted, but not when
* a #WnckWindow::state-changed gets emitted.
*
* Return value: %TRUE if @window is on all workspaces, %FALSE otherwise.
**/
gboolean
wnck_window_is_pinned (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window->priv->workspace == ALL_WORKSPACES;
}
/**
* wnck_window_pin:
* @window: a #WnckWindow.
*
* Asks the window manager to put @window on all workspaces.
**/
void
wnck_window_pin (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_change_workspace (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
ALL_WORKSPACES);
}
/**
* wnck_window_unpin:
* @window: a #WnckWindow.
*
* Asks the window manager to put @window only in the currently active
* workspace, if @window was previously pinned. If @window was not pinned,
* does not change @window's workspace. If the active workspace
* is not known for some reason (it should not happen much), sets
* @window's workspace to the first workspace.
**/
void
wnck_window_unpin (WnckWindow *window)
{
WnckWorkspace *active;
g_return_if_fail (WNCK_IS_WINDOW (window));
if (window->priv->workspace != ALL_WORKSPACES)
return;
active = wnck_screen_get_active_workspace (window->priv->screen);
_wnck_change_workspace (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
active ? wnck_workspace_get_number (active) : 0);
}
/**
* wnck_window_activate:
* @window: a #WnckWindow.
* @timestamp: the X server timestamp of the user interaction event that caused
* this call to occur.
*
* Asks the window manager to make @window the active window. The
* window manager may choose to raise @window along with focusing it, and may
* decide to refuse the request (to not steal the focus if there is a more
* recent user activity, for example).
*
* This function existed before 2.10, but the @timestamp argument was missing
* in earlier versions.
*
* Since: 2.10
**/
void
wnck_window_activate (WnckWindow *window,
guint32 timestamp)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
_wnck_activate (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
timestamp);
}
/**
* wnck_window_is_active:
* @window: a #WnckWindow.
*
* Gets whether @window is the active window on its #WnckScreen.
*
* Return value: %TRUE if @window is the active window on its #WnckScreen,
* %FALSE otherwise.
**/
gboolean
wnck_window_is_active (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return window == wnck_screen_get_active_window (window->priv->screen);
}
/**
* wnck_window_is_most_recently_activated:
* @window: a #WnckWindow.
*
* Gets whether @window is the most recently activated window on its
* #WnckScreen.
*
* The most recently activated window is identical to the active
* window for click and sloppy focus methods (since a window is always
* active in those cases) but differs slightly for mouse focus since
* there often is no active window.
*
* Return value: %TRUE if @window was the most recently activated window on its
* #WnckScreen, %FALSE otherwise.
*
* Since: 2.8
**/
gboolean
wnck_window_is_most_recently_activated (WnckWindow *window)
{
WnckWindow * current;
WnckWindow * previous;
WnckWindow * most_recently_activated_window;
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
current = wnck_screen_get_active_window (window->priv->screen);
previous = wnck_screen_get_previously_active_window (window->priv->screen);
if (current)
most_recently_activated_window = current;
else
most_recently_activated_window = previous;
return (window == most_recently_activated_window);
}
static WnckWindow*
find_last_transient_for (GList *windows,
Window xwindow)
{
GList *tmp;
WnckWindow *retval;
/* find _last_ transient for xwindow in the list */
retval = NULL;
tmp = windows;
while (tmp != NULL)
{
WnckWindow *w = tmp->data;
if (w->priv->transient_for == xwindow &&
w->priv->wintype != WNCK_WINDOW_UTILITY)
retval = w;
tmp = tmp->next;
}
return retval;
}
/**
* wnck_window_activate_transient:
* @window: a #WnckWindow.
* @timestamp: the X server timestamp of the user interaction event that caused
* this call to occur.
*
* If @window has transients, activates the most likely transient
* instead of the window itself. Otherwise activates @window.
*
* FIXME the ideal behavior of this function is probably to activate
* the most recently active window among @window and its transients.
* This is probably best implemented on the window manager side.
*
* This function existed before 2.10, but the @timestamp argument was missing
* in earlier versions.
*
* Since: 2.10
**/
void
wnck_window_activate_transient (WnckWindow *window,
guint32 timestamp)
{
GList *windows;
WnckWindow *transient;
WnckWindow *next;
g_return_if_fail (WNCK_IS_WINDOW (window));
windows = wnck_screen_get_windows_stacked (window->priv->screen);
transient = NULL;
next = find_last_transient_for (windows, window->priv->xwindow);
while (next != NULL)
{
if (next == window)
{
/* catch transient cycles */
transient = NULL;
break;
}
transient = next;
next = find_last_transient_for (windows, transient->priv->xwindow);
}
if (transient != NULL)
wnck_window_activate (transient, timestamp);
else
wnck_window_activate (window, timestamp);
}
/**
* wnck_window_transient_is_most_recently_activated:
* @window: a #WnckWindow.
*
* Gets whether one of the transients of @window is the most
* recently activated window. See
* wnck_window_is_most_recently_activated() for a more complete
* description of what is meant by most recently activated. This
* function is needed because clicking on a #WnckTasklist once will
* activate a transient instead of @window itself
* (wnck_window_activate_transient), and clicking again should
* minimize @window and its transients. (Not doing this can be
* especially annoying in the case of modal dialogs that don't appear
* in the #WnckTasklist).
*
* Return value: %TRUE if one of the transients of @window is the most recently
* activated window, %FALSE otherwise.
*
* Since: 2.12
**/
gboolean
wnck_window_transient_is_most_recently_activated (WnckWindow *window)
{
GList *windows;
WnckWindow *transient;
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
windows = wnck_screen_get_windows_stacked (window->priv->screen);
transient = window;
while ((transient = find_last_transient_for (windows, transient->priv->xwindow)))
{
/* catch transient cycles */
if (transient == window)
return FALSE;
if (wnck_window_is_most_recently_activated (transient))
return TRUE;
}
return FALSE;
}
static void
get_icons (WnckWindow *window)
{
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
gsize normal_size;
gsize mini_size;
icon = NULL;
mini_icon = NULL;
normal_size = _wnck_get_default_icon_size ();
mini_size = _wnck_get_default_mini_icon_size ();
if (_wnck_read_icons (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
window->priv->icon_cache,
&icon, normal_size, normal_size,
&mini_icon, mini_size, mini_size))
{
window->priv->need_emit_icon_changed = TRUE;
if (window->priv->icon)
g_object_unref (G_OBJECT (window->priv->icon));
if (window->priv->mini_icon)
g_object_unref (G_OBJECT (window->priv->mini_icon));
window->priv->icon = icon;
window->priv->mini_icon = mini_icon;
}
g_assert ((window->priv->icon && window->priv->mini_icon) ||
!(window->priv->icon || window->priv->mini_icon));
}
void
_wnck_window_load_icons (WnckWindow *window)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
get_icons (window);
if (window->priv->need_emit_icon_changed)
queue_update (window); /* not done in get_icons since we call that from
* the update
*/
}
/**
* wnck_window_get_icon:
* @window: a #WnckWindow.
*
* Gets the icon to be used for @window. If no icon was found, a fallback
* icon is used. wnck_window_get_icon_is_fallback() can be used to tell if the
* icon is the fallback icon.
*
* Return value: (transfer none): the icon for @window. The caller should
* reference the returned GdkPixbuf if it needs to keep
* the icon around.
**/
GdkPixbuf*
wnck_window_get_icon (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
_wnck_window_load_icons (window);
return window->priv->icon;
}
/**
* wnck_window_get_mini_icon:
* @window: a #WnckWindow.
*
* Gets the mini-icon to be used for @window. If no mini-icon was found, a
* fallback mini-icon is used. wnck_window_get_icon_is_fallback() can be used
* to tell if the mini-icon is the fallback mini-icon.
*
* Return value: (transfer none): the mini-icon for @window. The caller should
* reference the returned GdkPixbuf if it needs to keep
* the icon around.
**/
GdkPixbuf*
wnck_window_get_mini_icon (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
_wnck_window_load_icons (window);
return window->priv->mini_icon;
}
/**
* wnck_window_get_icon_is_fallback:
* @window: a #WnckWindow.
*
* Gets whether a default fallback icon is used for @window (because none
* was set on @window).
*
* Return value: %TRUE if the icon for @window is a fallback, %FALSE otherwise.
**/
gboolean
wnck_window_get_icon_is_fallback (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
return _wnck_icon_cache_get_is_fallback (window->priv->icon_cache);
}
/**
* wnck_window_get_actions:
* @window: a #WnckWindow.
*
* Gets the actions that can be done for @window.
*
* Return value: bitmask of actions that can be done for @window.
**/
WnckWindowActions
wnck_window_get_actions (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
return window->priv->actions;
}
/**
* wnck_window_get_state:
* @window: a #WnckWindow.
*
* Gets the state of @window.
*
* Return value: bitmask of active states for @window.
**/
WnckWindowState
wnck_window_get_state (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), 0);
return COMPRESS_STATE (window);
}
/**
* wnck_window_get_client_window_geometry:
* @window: a #WnckWindow.
* @xp: (out): return location for X coordinate in pixels of @window.
* @yp: (out): return location for Y coordinate in pixels of @window.
* @widthp: (out): return location for width in pixels of @window.
* @heightp: (out): return location for height in pixels of @window.
*
* Gets the size and position of @window, as last received
* in a ConfigureNotify event (i.e. this call does not round-trip
* to the server, just gets the last size we were notified of).
* The X and Y coordinates are relative to the root window.
*
* The window manager usually adds a frame around windows. If
* you need to know the size of @window with the frame, use
* wnck_window_get_geometry().
*
* Since: 2.20
**/
void
wnck_window_get_client_window_geometry (WnckWindow *window,
int *xp,
int *yp,
int *widthp,
int *heightp)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
if (xp)
*xp = window->priv->x;
if (yp)
*yp = window->priv->y;
if (widthp)
*widthp = window->priv->width;
if (heightp)
*heightp = window->priv->height;
}
/**
* wnck_window_get_geometry:
* @window: a #WnckWindow.
* @xp: (out): return location for X coordinate in pixels of @window.
* @yp: (out): return location for Y coordinate in pixels of @window.
* @widthp: (out): return location for width in pixels of @window.
* @heightp: (out): return location for height in pixels of @window.
*
* Gets the size and position of @window, including decorations. This
* function uses the information last received in a ConfigureNotify
* event and adjusts it according to the size of the frame that is
* added by the window manager (this call does not round-trip to the
* server, it just gets the last sizes that were notified). The
* X and Y coordinates are relative to the root window.
*
* If you need to know the actual size of @window ignoring the frame
* added by the window manager, use wnck_window_get_client_window_geometry().
**/
void
wnck_window_get_geometry (WnckWindow *window,
int *xp,
int *yp,
int *widthp,
int *heightp)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
if (xp)
*xp = window->priv->x - window->priv->left_frame;
if (yp)
*yp = window->priv->y - window->priv->top_frame;
if (widthp)
*widthp = window->priv->width + window->priv->left_frame + window->priv->right_frame;
if (heightp)
*heightp = window->priv->height + window->priv->top_frame + window->priv->bottom_frame;
}
/**
* wnck_window_set_geometry:
* @window: a #WnckWindow.
* @gravity: the gravity point to use as a reference for the new position.
* @geometry_mask: a bitmask containing flags for what should be set.
* @x: new X coordinate in pixels of @window.
* @y: new Y coordinate in pixels of @window.
* @width: new width in pixels of @window.
* @height: new height in pixels of @window.
*
* Sets the size and position of @window. The X and Y coordinates should be
* relative to the root window.
*
* Note that the new size and position apply to @window with its frame added
* by the window manager. Therefore, using wnck_window_set_geometry() with
* the values returned by wnck_window_get_geometry() should be a no-op, while
* using wnck_window_set_geometry() with the values returned by
* wnck_window_get_client_window_geometry() should reduce the size of @window
* and move it.
*
* Since: 2.16
**/
void
wnck_window_set_geometry (WnckWindow *window,
WnckWindowGravity gravity,
WnckWindowMoveResizeMask geometry_mask,
int x,
int y,
int width,
int height)
{
int gravity_and_flags;
int source;
g_return_if_fail (WNCK_IS_WINDOW (window));
source = _wnck_get_client_type();
gravity_and_flags = gravity;
gravity_and_flags |= geometry_mask << 8;
gravity_and_flags |= source << 12;
x += window->priv->left_frame;
y += window->priv->top_frame;
width -= window->priv->left_frame + window->priv->right_frame;
height -= window->priv->top_frame + window->priv->bottom_frame;
_wnck_set_window_geometry (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
gravity_and_flags, x, y, width, height);
}
/**
* wnck_window_is_visible_on_workspace:
* @window: a #WnckWindow.
* @workspace: a #WnckWorkspace.
*
* Like wnck_window_is_on_workspace(), but also checks that
* the window is in a visible state (i.e. not minimized or shaded).
*
* Return value: %TRUE if @window appears on @workspace in normal state, %FALSE
* otherwise.
**/
gboolean
wnck_window_is_visible_on_workspace (WnckWindow *window,
WnckWorkspace *workspace)
{
WnckWindowState state;
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
g_return_val_if_fail (WNCK_IS_WORKSPACE (workspace), FALSE);
state = wnck_window_get_state (window);
if (state & WNCK_WINDOW_STATE_HIDDEN)
return FALSE; /* not visible */
return wnck_window_is_on_workspace (window, workspace);
}
/**
* wnck_window_set_icon_geometry:
* @window: a #WnckWindow.
* @x: X coordinate in pixels.
* @y: Y coordinate in pixels.
* @width: width in pixels.
* @height: height in pixels.
*
* Sets the icon geometry for @window. A typical use case for this is the
* destination of the minimization animation of @window.
*/
void
wnck_window_set_icon_geometry (WnckWindow *window,
int x,
int y,
int width,
int height)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
if (window->priv->icon_geometry.x == x &&
window->priv->icon_geometry.y == y &&
window->priv->icon_geometry.width == width &&
window->priv->icon_geometry.height == height)
return;
window->priv->icon_geometry.x = x;
window->priv->icon_geometry.y = y;
window->priv->icon_geometry.width = width;
window->priv->icon_geometry.height = height;
_wnck_set_icon_geometry (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
x, y, width, height);
}
/**
* wnck_window_is_on_workspace:
* @window: a #WnckWindow.
* @workspace: a #WnckWorkspace.
*
* Gets whether @window appears on @workspace.
*
* Return value: %TRUE if @window appears on @workspace, %FALSE otherwise.
**/
gboolean
wnck_window_is_on_workspace (WnckWindow *window,
WnckWorkspace *workspace)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
g_return_val_if_fail (WNCK_IS_WORKSPACE (workspace), FALSE);
return wnck_window_is_pinned (window) ||
wnck_window_get_workspace (window) == workspace;
}
/**
* wnck_window_is_in_viewport:
* @window: a #WnckWindow.
* @workspace: a #WnckWorkspace.
*
* Gets %TRUE if @window appears in the current viewport of @workspace.
*
* Return value: %TRUE if @window appears in current viewport of @workspace,
* %FALSE otherwise.
*
* Since: 2.4
**/
gboolean
wnck_window_is_in_viewport (WnckWindow *window,
WnckWorkspace *workspace)
{
GdkRectangle window_rect;
GdkRectangle viewport_rect;
g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
g_return_val_if_fail (WNCK_IS_WORKSPACE (workspace), FALSE);
if (wnck_window_is_pinned (window) )
return TRUE;
if (wnck_window_get_workspace (window) != workspace)
return FALSE;
viewport_rect.x = wnck_workspace_get_viewport_x (workspace);
viewport_rect.y = wnck_workspace_get_viewport_y (workspace);
viewport_rect.width = wnck_screen_get_width (window->priv->screen);
viewport_rect.height = wnck_screen_get_height (window->priv->screen);
window_rect.x = window->priv->x - window->priv->left_frame + viewport_rect.x;
window_rect.y = window->priv->y - window->priv->top_frame + viewport_rect.y;
window_rect.width = window->priv->width + window->priv->left_frame + window->priv->right_frame;
window_rect.height = window->priv->height + window->priv->top_frame + window->priv->bottom_frame;
return gdk_rectangle_intersect (&viewport_rect, &window_rect, &window_rect);
}
void
_wnck_window_set_application (WnckWindow *window,
WnckApplication *app)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
g_return_if_fail (app == NULL || WNCK_IS_APPLICATION (app));
if (app)
g_object_ref (G_OBJECT (app));
if (window->priv->app)
g_object_unref (G_OBJECT (window->priv->app));
window->priv->app = app;
}
void
_wnck_window_set_class_group (WnckWindow *window,
WnckClassGroup *class_group)
{
g_return_if_fail (WNCK_IS_WINDOW (window));
g_return_if_fail (class_group == NULL || WNCK_IS_CLASS_GROUP (class_group));
if (class_group)
g_object_ref (G_OBJECT (class_group));
if (window->priv->class_group)
g_object_unref (G_OBJECT (window->priv->class_group));
window->priv->class_group = class_group;
}
void
_wnck_window_process_property_notify (WnckWindow *window,
XEvent *xevent)
{
if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_STATE"))
{
window->priv->need_update_state = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("WM_STATE"))
{
window->priv->need_update_wm_state = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
XA_WM_NAME ||
xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_NAME") ||
xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_VISIBLE_NAME"))
{
window->priv->need_update_name = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
XA_WM_ICON_NAME ||
xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_ICON_NAME") ||
xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_VISIBLE_ICON_NAME"))
{
window->priv->need_update_icon_name = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_ALLOWED_ACTIONS"))
{
window->priv->need_update_actions = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_DESKTOP"))
{
window->priv->need_update_workspace = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_WINDOW_TYPE"))
{
window->priv->need_update_wintype = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("WM_TRANSIENT_FOR"))
{
window->priv->need_update_transient_for = TRUE;
window->priv->need_update_wintype = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_STARTUP_ID"))
{
window->priv->need_update_startup_id = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom == XA_WM_CLASS)
{
window->priv->need_update_wmclass = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_WM_ICON") ||
xevent->xproperty.atom ==
_wnck_atom_get ("KWM_WIN_ICON"))
{
_wnck_icon_cache_property_changed (window->priv->icon_cache,
xevent->xproperty.atom);
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("WM_HINTS"))
{
window->priv->need_update_wmhints = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("_NET_FRAME_EXTENTS") ||
xevent->xproperty.atom ==
_wnck_atom_get ("_GTK_FRAME_EXTENTS"))
{
window->priv->need_update_frame_extents = TRUE;
queue_update (window);
}
else if (xevent->xproperty.atom ==
_wnck_atom_get ("WM_WINDOW_ROLE"))
{
window->priv->need_update_role = TRUE;
queue_update (window);
}
}
void
_wnck_window_process_configure_notify (WnckWindow *window,
XEvent *xevent)
{
if (xevent->xconfigure.send_event)
{
window->priv->x = xevent->xconfigure.x;
window->priv->y = xevent->xconfigure.y;
}
else
{
_wnck_get_window_position (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
&window->priv->x,
&window->priv->y);
}
window->priv->width = xevent->xconfigure.width;
window->priv->height = xevent->xconfigure.height;
emit_geometry_changed (window);
}
static void
update_wm_state (WnckWindow *window)
{
int state;
if (!window->priv->need_update_wm_state)
return;
window->priv->need_update_wm_state = FALSE;
window->priv->wm_state_iconic = FALSE;
state = _wnck_get_wm_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
if (state == IconicState)
window->priv->wm_state_iconic = TRUE;
}
static void
update_state (WnckWindow *window)
{
Atom *atoms;
int n_atoms;
int i;
gboolean reread_net_wm_state;
reread_net_wm_state = window->priv->need_update_state;
window->priv->need_update_state = FALSE;
/* This is a bad hack, we always add the
* state based on window type in to the state,
* even if no state update is pending (since the
* state update just means the _NET_WM_STATE prop
* changed
*/
if (reread_net_wm_state)
{
gboolean demanded_attention;
demanded_attention = window->priv->demands_attention;
window->priv->is_maximized_horz = FALSE;
window->priv->is_maximized_vert = FALSE;
window->priv->is_sticky = FALSE;
window->priv->is_shaded = FALSE;
window->priv->is_above = FALSE;
window->priv->is_below = FALSE;
window->priv->skip_taskbar = FALSE;
window->priv->skip_pager = FALSE;
window->priv->net_wm_state_hidden = FALSE;
window->priv->is_fullscreen = FALSE;
window->priv->demands_attention = FALSE;
atoms = NULL;
n_atoms = 0;
_wnck_get_atom_list (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("_NET_WM_STATE"),
&atoms, &n_atoms);
i = 0;
while (i < n_atoms)
{
if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_VERT"))
window->priv->is_maximized_vert = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_MAXIMIZED_HORZ"))
window->priv->is_maximized_horz = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_HIDDEN"))
window->priv->net_wm_state_hidden = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_STICKY"))
window->priv->is_sticky = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SHADED"))
window->priv->is_shaded = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_ABOVE"))
window->priv->is_above = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_BELOW"))
window->priv->is_below = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_FULLSCREEN"))
window->priv->is_fullscreen = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SKIP_TASKBAR"))
window->priv->skip_taskbar = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SKIP_PAGER"))
window->priv->skip_pager = TRUE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_DEMANDS_ATTENTION"))
window->priv->demands_attention = TRUE;
++i;
}
if (window->priv->demands_attention != demanded_attention)
{
if (window->priv->demands_attention)
time (&window->priv->needs_attention_time);
else if (!window->priv->is_urgent)
window->priv->needs_attention_time = 0;
}
g_free (atoms);
}
switch (window->priv->wintype)
{
case WNCK_WINDOW_DESKTOP:
case WNCK_WINDOW_DOCK:
case WNCK_WINDOW_SPLASHSCREEN:
window->priv->skip_taskbar = TRUE;
break;
case WNCK_WINDOW_TOOLBAR:
case WNCK_WINDOW_MENU:
case WNCK_WINDOW_UTILITY:
case WNCK_WINDOW_DIALOG:
/* Skip taskbar if the window is transient
* for some main application window
*/
if (wnck_window_get_transient (window) != NULL &&
!window->priv->transient_for_root)
window->priv->skip_taskbar = TRUE;
break;
case WNCK_WINDOW_NORMAL:
default:
break;
}
/* FIXME!!!!!!!!!! What in the world is this buggy duplicate of the code
* immediately above this for??!?!?
*/
switch (window->priv->wintype)
{
case WNCK_WINDOW_DESKTOP:
case WNCK_WINDOW_DOCK:
case WNCK_WINDOW_TOOLBAR:
case WNCK_WINDOW_MENU:
case WNCK_WINDOW_SPLASHSCREEN:
window->priv->skip_pager = TRUE;
break;
case WNCK_WINDOW_NORMAL:
case WNCK_WINDOW_DIALOG:
case WNCK_WINDOW_UTILITY:
default:
break;
}
/* FIXME we need to recompute this if the window manager changes */
if (wnck_screen_net_wm_supports (window->priv->screen,
"_NET_WM_STATE_HIDDEN"))
{
window->priv->is_hidden = window->priv->net_wm_state_hidden;
/* FIXME this is really broken; need to bring it up on
* wm-spec-list. It results in showing an "Unminimize" menu
* item on task list, for shaded windows.
*/
window->priv->is_minimized = window->priv->is_hidden;
}
else
{
window->priv->is_minimized = window->priv->wm_state_iconic;
window->priv->is_hidden = window->priv->is_minimized || window->priv->is_shaded;
}
}
static void
update_name (WnckWindow *window)
{
char *new_name;
if (!window->priv->need_update_name)
return;
window->priv->need_update_name = FALSE;
new_name = _wnck_get_name (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
if (g_strcmp0 (window->priv->name, new_name) != 0)
window->priv->need_emit_name_changed = TRUE;
g_free (window->priv->name);
window->priv->name = new_name;
}
static void
update_icon_name (WnckWindow *window)
{
char *new_name = NULL;
if (!window->priv->need_update_icon_name)
return;
window->priv->need_update_icon_name = FALSE;
new_name = _wnck_get_icon_name (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow);
if (g_strcmp0 (window->priv->icon_name, new_name) != 0)
window->priv->need_emit_name_changed = TRUE;
g_free (window->priv->icon_name);
window->priv->icon_name = new_name;
}
static void
update_workspace (WnckWindow *window)
{
int val;
int old;
if (!window->priv->need_update_workspace)
return;
window->priv->need_update_workspace = FALSE;
old = window->priv->workspace;
val = ALL_WORKSPACES;
_wnck_get_cardinal (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("_NET_WM_DESKTOP"),
&val);
window->priv->workspace = val;
if (old != window->priv->workspace)
emit_workspace_changed (window);
}
static void
update_actions (WnckWindow *window)
{
Atom *atoms;
int n_atoms;
int i;
if (!window->priv->need_update_actions)
return;
window->priv->need_update_actions = FALSE;
window->priv->actions = 0;
atoms = NULL;
n_atoms = 0;
if (!_wnck_get_atom_list (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("_NET_WM_ALLOWED_ACTIONS"),
&atoms,
&n_atoms))
{
window->priv->actions =
WNCK_WINDOW_ACTION_MOVE |
WNCK_WINDOW_ACTION_RESIZE |
WNCK_WINDOW_ACTION_SHADE |
WNCK_WINDOW_ACTION_STICK |
WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY |
WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY |
WNCK_WINDOW_ACTION_CHANGE_WORKSPACE |
WNCK_WINDOW_ACTION_CLOSE |
WNCK_WINDOW_ACTION_UNMAXIMIZE_HORIZONTALLY |
WNCK_WINDOW_ACTION_UNMAXIMIZE_VERTICALLY |
WNCK_WINDOW_ACTION_UNSHADE |
WNCK_WINDOW_ACTION_UNSTICK |
WNCK_WINDOW_ACTION_MINIMIZE |
WNCK_WINDOW_ACTION_UNMINIMIZE |
WNCK_WINDOW_ACTION_MAXIMIZE |
WNCK_WINDOW_ACTION_UNMAXIMIZE |
WNCK_WINDOW_ACTION_FULLSCREEN |
WNCK_WINDOW_ACTION_ABOVE |
WNCK_WINDOW_ACTION_BELOW;
return;
}
i = 0;
while (i < n_atoms)
{
if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_MOVE"))
window->priv->actions |= WNCK_WINDOW_ACTION_MOVE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_RESIZE"))
window->priv->actions |= WNCK_WINDOW_ACTION_RESIZE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_SHADE"))
window->priv->actions |= WNCK_WINDOW_ACTION_SHADE |
WNCK_WINDOW_ACTION_UNSHADE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_STICK"))
window->priv->actions |= WNCK_WINDOW_ACTION_STICK |
WNCK_WINDOW_ACTION_UNSTICK;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_MINIMIZE"))
window->priv->actions |= WNCK_WINDOW_ACTION_MINIMIZE |
WNCK_WINDOW_ACTION_UNMINIMIZE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_MAXIMIZE_HORZ"))
window->priv->actions |= WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY |
WNCK_WINDOW_ACTION_UNMAXIMIZE_HORIZONTALLY;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_MAXIMIZE_VERT"))
window->priv->actions |= WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY |
WNCK_WINDOW_ACTION_UNMAXIMIZE_VERTICALLY;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_CHANGE_DESKTOP"))
window->priv->actions |= WNCK_WINDOW_ACTION_CHANGE_WORKSPACE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_CLOSE"))
window->priv->actions |= WNCK_WINDOW_ACTION_CLOSE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_FULLSCREEN"))
window->priv->actions |= WNCK_WINDOW_ACTION_FULLSCREEN;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_ABOVE"))
window->priv->actions |= WNCK_WINDOW_ACTION_ABOVE;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_ACTION_BELOW"))
window->priv->actions |= WNCK_WINDOW_ACTION_BELOW;
else
{
const char *name = _wnck_atom_name (atoms [i]);
if (name && g_str_has_prefix (name, "_NET_WM_"))
g_warning ("Unhandled action type %s", name);
}
i++;
}
g_free (atoms);
if ((window->priv->actions & WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY) &&
(window->priv->actions & WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY))
window->priv->actions |=
WNCK_WINDOW_ACTION_MAXIMIZE |
WNCK_WINDOW_ACTION_UNMAXIMIZE;
}
static void
update_wintype (WnckWindow *window)
{
Atom *atoms;
int n_atoms;
WnckWindowType type;
gboolean found_type;
if (!window->priv->need_update_wintype)
return;
window->priv->need_update_wintype = FALSE;
found_type = FALSE;
type = WNCK_WINDOW_NORMAL;
atoms = NULL;
n_atoms = 0;
if (_wnck_get_atom_list (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("_NET_WM_WINDOW_TYPE"),
&atoms,
&n_atoms))
{
int i;
i = 0;
while (i < n_atoms && !found_type)
{
/* We break as soon as we find one we recognize,
* supposed to prefer those near the front of the list
*/
found_type = TRUE;
if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DESKTOP"))
type = WNCK_WINDOW_DESKTOP;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DOCK"))
type = WNCK_WINDOW_DOCK;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_TOOLBAR"))
type = WNCK_WINDOW_TOOLBAR;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_MENU"))
type = WNCK_WINDOW_MENU;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_DIALOG"))
type = WNCK_WINDOW_DIALOG;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_NORMAL"))
type = WNCK_WINDOW_NORMAL;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_UTILITY"))
type = WNCK_WINDOW_UTILITY;
else if (atoms[i] == _wnck_atom_get ("_NET_WM_WINDOW_TYPE_SPLASH"))
type = WNCK_WINDOW_SPLASHSCREEN;
else
found_type = FALSE;
++i;
}
g_free (atoms);
}
if (!found_type)
{
if (window->priv->transient_for != None)
{
type = WNCK_WINDOW_DIALOG;
}
else
{
type = WNCK_WINDOW_NORMAL;
}
found_type = TRUE;
}
if (window->priv->wintype != type)
{
window->priv->need_emit_type_changed = TRUE;
window->priv->wintype = type;
}
}
static void
update_transient_for (WnckWindow *window)
{
Window parent;
if (!window->priv->need_update_transient_for)
return;
window->priv->need_update_transient_for = FALSE;
parent = None;
if (_wnck_get_window (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("WM_TRANSIENT_FOR"),
&parent) &&
parent != window->priv->xwindow)
{
window->priv->transient_for = parent;
if (wnck_screen_get_for_root (window->priv->transient_for) != NULL)
window->priv->transient_for_root = TRUE;
else
window->priv->transient_for_root = FALSE;
}
else
{
window->priv->transient_for = None;
window->priv->transient_for_root = FALSE;
}
}
static void
update_startup_id (WnckWindow *window)
{
if (!window->priv->need_update_startup_id)
return;
window->priv->need_update_startup_id = FALSE;
g_free (window->priv->startup_id);
window->priv->startup_id =
_wnck_get_utf8_property (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("_NET_STARTUP_ID"));
}
static void
update_wmclass (WnckWindow *window)
{
char *new_res_class = NULL;
char *new_res_name = NULL;
if (!window->priv->need_update_wmclass)
return;
window->priv->need_update_wmclass = FALSE;
_wnck_get_wmclass (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
&new_res_class,
&new_res_name);
if (g_strcmp0 (window->priv->res_class, new_res_class) != 0 ||
g_strcmp0 (window->priv->res_name, new_res_name) != 0)
{
window->priv->need_emit_class_changed = TRUE;
g_free (window->priv->res_class);
g_free (window->priv->res_name);
window->priv->res_class = new_res_class;
window->priv->res_name = new_res_name;
}
else
{
g_free (new_res_class);
g_free (new_res_name);
}
}
static void
update_wmhints (WnckWindow *window)
{
Display *display;
XWMHints *hints;
if (!window->priv->need_update_wmhints)
return;
display = _wnck_window_get_display (window);
_wnck_error_trap_push (display);
hints = XGetWMHints (display, window->priv->xwindow);
_wnck_error_trap_pop (display);
if (hints)
{
if ((hints->flags & IconPixmapHint) ||
(hints->flags & IconMaskHint))
_wnck_icon_cache_property_changed (window->priv->icon_cache,
_wnck_atom_get ("WM_HINTS"));
if (hints->flags & WindowGroupHint)
window->priv->group_leader = hints->window_group;
if (hints->flags & XUrgencyHint)
{
window->priv->is_urgent = TRUE;
time (&window->priv->needs_attention_time);
}
else
{
window->priv->is_urgent = FALSE;
if (!window->priv->demands_attention)
window->priv->needs_attention_time = 0;
}
XFree (hints);
}
window->priv->need_update_wmhints = FALSE;
}
static void
update_frame_extents (WnckWindow *window)
{
int left, right, top, bottom;
if (!window->priv->need_update_frame_extents)
return;
window->priv->need_update_frame_extents = FALSE;
left = right = top = bottom = 0;
if (!_wnck_get_frame_extents (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
&left, &right, &top, &bottom))
return;
if (left != window->priv->left_frame ||
right != window->priv->right_frame ||
top != window->priv->top_frame ||
bottom != window->priv->bottom_frame)
{
window->priv->left_frame = left;
window->priv->right_frame = right;
window->priv->top_frame = top;
window->priv->bottom_frame = bottom;
emit_geometry_changed (window);
}
}
static void
update_role (WnckWindow *window)
{
char *new_role;
if (!window->priv->need_update_role)
return;
window->priv->need_update_role = FALSE;
new_role = _wnck_get_text_property (WNCK_SCREEN_XSCREEN (window->priv->screen),
window->priv->xwindow,
_wnck_atom_get ("WM_WINDOW_ROLE"));
if (g_strcmp0 (window->priv->role, new_role) != 0)
{
window->priv->need_emit_role_changed = TRUE;
g_free (window->priv->role);
window->priv->role = new_role;
}
else
{
g_free (new_role);
}
}
static void
force_update_now (WnckWindow *window)
{
WnckWindowState old_state;
WnckWindowState new_state;
WnckWindowActions old_actions;
unqueue_update (window);
/* Name must be done before all other stuff,
* because we have iconsistent state across the
* update_name/update_icon_name functions (no window name),
* and we have to fix that before we emit any other signals
*/
update_name (window);
update_icon_name (window);
if (window->priv->need_emit_name_changed)
emit_name_changed (window);
old_state = COMPRESS_STATE (window);
old_actions = window->priv->actions;
update_startup_id (window); /* no side effects */
update_wmclass (window);
update_wmhints (window);
update_transient_for (window); /* wintype needs this to be first */
update_wintype (window); /* emits signals */
update_wm_state (window);
update_state (window); /* must come after the above, since they affect
* our calculated state
*/
update_workspace (window); /* emits signals */
update_actions (window);
update_frame_extents (window); /* emits signals */
update_role (window); /* emits signals */
get_icons (window);
new_state = COMPRESS_STATE (window);
if (old_state != new_state)
emit_state_changed (window, old_state ^ new_state, new_state);
if (old_actions != window->priv->actions)
emit_actions_changed (window, old_actions ^ window->priv->actions,
window->priv->actions);
if (window->priv->need_emit_icon_changed)
emit_icon_changed (window);
if (window->priv->need_emit_class_changed)
emit_class_changed (window);
if (window->priv->need_emit_role_changed)
emit_role_changed (window);
if (window->priv->need_emit_type_changed)
emit_type_changed (window);
}
static gboolean
update_idle (gpointer data)
{
WnckWindow *window = WNCK_WINDOW (data);
window->priv->update_handler = 0;
force_update_now (window);
return FALSE;
}
static void
queue_update (WnckWindow *window)
{
if (window->priv->update_handler != 0)
return;
window->priv->update_handler = g_idle_add (update_idle, window);
}
static void
unqueue_update (WnckWindow *window)
{
if (window->priv->update_handler != 0)
{
g_source_remove (window->priv->update_handler);
window->priv->update_handler = 0;
}
}
static void
emit_name_changed (WnckWindow *window)
{
window->priv->need_emit_name_changed = FALSE;
g_signal_emit (G_OBJECT (window),
signals[NAME_CHANGED],
0);
}
static void
emit_state_changed (WnckWindow *window,
WnckWindowState changed_mask,
WnckWindowState new_state)
{
g_signal_emit (G_OBJECT (window),
signals[STATE_CHANGED],
0, changed_mask, new_state);
}
static void
emit_workspace_changed (WnckWindow *window)
{
g_signal_emit (G_OBJECT (window),
signals[WORKSPACE_CHANGED],
0);
}
static void
emit_icon_changed (WnckWindow *window)
{
window->priv->need_emit_icon_changed = FALSE;
g_signal_emit (G_OBJECT (window),
signals[ICON_CHANGED],
0);
}
static void
emit_class_changed (WnckWindow *window)
{
window->priv->need_emit_class_changed = FALSE;
g_signal_emit (G_OBJECT (window),
signals[CLASS_CHANGED],
0);
}
static void
emit_actions_changed (WnckWindow *window,
WnckWindowActions changed_mask,
WnckWindowActions new_actions)
{
g_signal_emit (G_OBJECT (window),
signals[ACTIONS_CHANGED],
0, changed_mask, new_actions);
}
static void
emit_geometry_changed (WnckWindow *window)
{
g_signal_emit (G_OBJECT (window),
signals[GEOMETRY_CHANGED],
0);
}
static void
emit_role_changed (WnckWindow *window)
{
window->priv->need_emit_role_changed = FALSE;
g_signal_emit (G_OBJECT (window),
signals[ROLE_CHANGED],
0);
}
static void
emit_type_changed (WnckWindow *window)
{
window->priv->need_emit_type_changed = FALSE;
g_signal_emit (G_OBJECT (window),
signals[TYPE_CHANGED],
0);
}