/* 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" #include "wnck-icon-cache-private.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) /* 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_WITH_PRIVATE (WnckWindow, wnck_window, G_TYPE_OBJECT); 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 }; static void wnck_window_init (WnckWindow *window) { window->priv = wnck_window_get_instance_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); 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) { return wnck_handle_get_window (_wnck_get_handle (), 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) { WnckHandle *handle; WnckWindow *window; Screen *xscreen; handle = wnck_screen_get_handle (screen); window = wnck_handle_get_window (handle, xwindow); g_return_val_if_fail (window == NULL, NULL); xscreen = WNCK_SCREEN_XSCREEN (screen); window = g_object_new (WNCK_TYPE_WINDOW, NULL); window->priv->xwindow = xwindow; window->priv->screen = screen; _wnck_handle_insert_window (handle, &window->priv->xwindow, window); /* Handle 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) { WnckHandle *handle; Window xwindow = window->priv->xwindow; g_return_if_fail (WNCK_IS_WINDOW (window)); handle = wnck_screen_get_handle (window->priv->screen); g_return_if_fail (wnck_handle_get_window (handle, xwindow) == window); _wnck_handle_remove_window (handle, &xwindow); /* Removing from handle also removes the only ref WnckWindow had */ g_return_if_fail (wnck_handle_get_window (handle, 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) { WnckHandle *handle; g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL); handle = wnck_screen_get_handle (window->priv->screen); return wnck_handle_get_window (handle, 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) { WnckHandle *handle; WnckApplication *app; /* Fall back to group leader property */ handle = wnck_screen_get_handle (window->priv->screen); app = wnck_handle_get_application (handle, 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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) { WnckHandle *handle; GdkPixbuf *icon; GdkPixbuf *mini_icon; gsize normal_size; gsize mini_size; handle = wnck_screen_get_handle (window->priv->screen); icon = NULL; mini_icon = NULL; normal_size = _wnck_handle_get_default_icon_size (handle); mini_size = _wnck_handle_get_default_mini_icon_size (handle); if (_wnck_read_icons (window->priv->screen, window->priv->xwindow, window->priv->icon_cache, &icon, normal_size, &mini_icon, 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) { WnckHandle *handle; int gravity_and_flags; int source; g_return_if_fail (WNCK_IS_WINDOW (window)); handle = wnck_screen_get_handle (window->priv->screen); source = _wnck_handle_get_client_type (handle); 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")) { _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) { WnckHandle *handle; WnckScreen *screen; window->priv->transient_for = parent; handle = wnck_screen_get_handle (window->priv->screen); screen = wnck_handle_get_screen_for_root (handle, window->priv->transient_for); if (screen != 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); }