| // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef WINDOW_MANAGER_WINDOW_H_ |
| #define WINDOW_MANAGER_WINDOW_H_ |
| |
| #include <cmath> |
| #include <ctime> |
| #include <deque> |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <tr1/memory> |
| #include <vector> |
| |
| #include <gtest/gtest_prod.h> // for FRIEND_TEST() macro |
| |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "cros/chromeos_wm_ipc_enums.h" |
| #include "window_manager/atom_cache.h" // for Atom enum |
| #include "window_manager/compositor/compositor.h" |
| #include "window_manager/geometry.h" |
| #include "window_manager/shadow.h" |
| #include "window_manager/wm_ipc.h" |
| #include "window_manager/x11/x_connection.h" |
| #include "window_manager/x11/x_types.h" |
| |
| namespace window_manager { |
| |
| class AnimationPair; |
| class DestroyedWindow; |
| struct Rect; |
| template<class T> class Stacker; // from util.h |
| class WindowManager; |
| |
| // A window created by another X client. |
| // |
| // Because we use the X composite extension, there are two separate positions of |
| // interest for a given window: |
| // |
| // - Where the client window is actually located on the X server. This is |
| // relevant for mouse input -- we shape the compositing overlay window so that |
| // events fall through it to the client windows underneath. |
| // - Where the window gets drawn on the compositing overlay window. It'll |
| // typically just be drawn in the same location as the actual client window, |
| // but we could also e.g. draw a scaled-down version of it in a different |
| // location. |
| // |
| // These two positions are not necessarily the same. When animating a window's |
| // position, it's desirable to just move the client window once to the final |
| // location and animate the move in the compositor. To display a window's |
| // contents onscreen but not let it receive any mouse events, we draw it in the |
| // compositor but move the client window offscreen. |
| // |
| // The new, preferred way to manage all of this is to call SetVisibility() to |
| // set a policy for the two windows and then use Move() to move the window. |
| // Move() handles placing the client window in the right place. |
| // |
| // The old approach, used by existing code, is for callers to not set a |
| // visibility policy and instead manage the client and composited windows |
| // separately. |
| class Window { |
| public: |
| enum Visibility { |
| // The old state of affairs: the client and composited windows are managed |
| // separately by the caller. This value is the default, but it cannot be |
| // passed to SetVisibility(). |
| VISIBILITY_UNSET = 0, |
| |
| // Don't display the window onscreen and don't let it receive mouse |
| // events. |
| VISIBILITY_HIDDEN = 1, |
| |
| // Display the window and let it receive mouse events. |
| VISIBILITY_SHOWN = 2, |
| |
| // Display the window but prevent it from receiving mouse events. |
| VISIBILITY_SHOWN_NO_INPUT = 3, |
| }; |
| |
| Window(WindowManager* wm, |
| XWindow xid, |
| bool override_redirect, |
| const XConnection::WindowGeometry& geometry); |
| ~Window(); |
| |
| XWindow xid() const { return xid_; } |
| const std::string& xid_str() const { return xid_str_; } |
| WindowManager* wm() { return wm_; } |
| Compositor::TexturePixmapActor* actor() { return actor_.get(); } |
| const Shadow* shadow() const { return shadow_.get(); } |
| XWindow transient_for_xid() const { return transient_for_xid_; } |
| bool override_redirect() const { return override_redirect_; } |
| chromeos::WmIpcWindowType type() const { return type_; } |
| const std::vector<int>& type_params() const { return type_params_; } |
| Visibility visibility() const { return visibility_; } |
| const char* type_str() const { |
| return chromeos::WmIpcWindowTypeToString(type_); |
| } |
| bool mapped() const { return mapped_; } |
| bool shaped() const { return shaped_; } |
| bool is_rgba() const { return client_depth_ == 32; } |
| bool client_has_redrawn_after_last_resize() const { |
| return client_has_redrawn_after_last_resize_; |
| } |
| |
| int client_x() const { return client_bounds_.x; } |
| int client_y() const { return client_bounds_.y; } |
| int client_width() const { return client_bounds_.width; } |
| int client_height() const { return client_bounds_.height; } |
| int client_depth() const { return client_depth_; } |
| Point client_origin() const { return client_bounds_.position(); } |
| Size client_size() const { return client_bounds_.size(); } |
| const Rect& client_bounds() const { return client_bounds_; } |
| |
| bool composited_shown() const { return composited_shown_; } |
| int composited_x() const { return composited_origin_.x; } |
| int composited_y() const { return composited_origin_.y; } |
| const Point& composited_origin() const { return composited_origin_; } |
| int composited_width() const { |
| return static_cast<int>(round(client_width() * composited_scale_x_)); |
| } |
| int composited_height() const { |
| return static_cast<int>(round(client_height() * composited_scale_y_)); |
| } |
| Size composited_size() const { |
| return Size(composited_width(), composited_height()); |
| } |
| double composited_scale_x() const { return composited_scale_x_; } |
| double composited_scale_y() const { return composited_scale_y_; } |
| double composited_opacity() const { return composited_opacity_; } |
| |
| // The client might've already requested that the window be translucent, |
| // in addition to whatever level has been set on the composited window. |
| double combined_opacity() const { |
| return composited_opacity_ * client_opacity_; |
| } |
| |
| const std::string& title() const { return title_; } |
| const XConnection::SizeHints& size_hints() const { return size_hints_; } |
| bool supports_wm_ping() const { return supports_wm_ping_; } |
| const std::vector<XAtom>& wm_window_type_xatoms() const { |
| return wm_window_type_xatoms_; |
| } |
| const std::set<XAtom>& chrome_state_xatoms() const { |
| return chrome_state_xatoms_; |
| } |
| bool wm_state_fullscreen() const { return wm_state_fullscreen_; } |
| bool wm_state_maximized_horz() const { return wm_state_maximized_horz_; } |
| bool wm_state_maximized_vert() const { return wm_state_maximized_vert_; } |
| bool wm_state_modal() const { return wm_state_modal_; } |
| bool wm_hint_urgent() const { return wm_hint_urgent_; } |
| const Rect& status_bounds() const { return status_bounds_; } |
| const std::string& client_hostname() const { return client_hostname_; } |
| int client_pid() const { return client_pid_; } |
| |
| // Have we received a pixmap for this window yet? If not, it won't be |
| // drawn onscreen. |
| bool has_initial_pixmap() const { return pixmap_ != 0; } |
| |
| // Are we currently showing the window's actor? |
| bool actor_is_shown() const { |
| return visibility_ == VISIBILITY_SHOWN || |
| visibility_ == VISIBILITY_SHOWN_NO_INPUT || |
| (visibility_ == VISIBILITY_UNSET && composited_shown_); |
| } |
| |
| // Is this window currently focused? We don't go to the X server for |
| // this; we just check with the FocusManager. |
| bool IsFocused() const; |
| |
| // Update |title_| based on _NET_WM_NAME. |
| void FetchAndApplyTitle(); |
| |
| // Get and apply hints that have been set for the client window. |
| bool FetchAndApplySizeHints(); |
| bool FetchAndApplyTransientHint(); |
| |
| // Update the window based on its Chrome OS window type property. |
| bool FetchAndApplyWindowType(); |
| |
| // Update the window's opacity in response to the current value of its |
| // _NET_WM_WINDOW_OPACITY property. |
| void FetchAndApplyWindowOpacity(); |
| |
| // Fetch the window's WM_HINTS property (ICCCM 4.1.2.4) if it exists and |
| // apply any changes that we see. |
| void FetchAndApplyWmHints(); |
| |
| // Fetch the window's WM_PROTOCOLS property (ICCCM 4.1.2.7) if it exists |
| // and update the various |supports_wm_*| members. Also calls |
| // FetchAndApplyWmSyncRequestCounter(), if the window claims to support |
| // _NET_WM_SYNC_REQUEST. |
| void FetchAndApplyWmProtocols(); |
| |
| // Fetch the window's _NET_WM_SYNC_REQUEST_COUNTER property (as described |
| // in EWMH) and ask the Sync extension to notify us whenever it changes. |
| bool FetchAndApplyWmSyncRequestCounterProperty(); |
| |
| // Fetch the window's _NET_WM_STATE property and update our internal copy |
| // of it. ClientMessage events should be used to update the states of mapped |
| // windows, so this is primarily useful for getting the initial state of the |
| // window before it's been mapped. |
| void FetchAndApplyWmState(); |
| |
| // Fetch the window's _NET_WM_WINDOW_TYPE property and update |
| // wm_window_type_atoms_. |
| void FetchAndApplyWmWindowType(); |
| |
| // Fetch the window's _CHROME_STATE property and update our internal copy |
| // of it. |
| void FetchAndApplyChromeState(); |
| |
| // Fetch the window's _CHROME_STATUS_BOUNDS property and update |
| // |status_bounds_|. |
| void FetchAndApplyChromeStatusBounds(); |
| |
| // Fetch the window's WM_CLIENT_MACHINE property and update |
| // |client_hostname_|. |
| void FetchAndApplyWmClientMachine(); |
| |
| // Fetch the window's _NET_WM_PID property and update |client_pid_|. |
| void FetchAndApplyWmPid(); |
| |
| // Check if the window has the _CHROME_FREEZE_UPDATES property set and call |
| // HandleFreezeUpdatesPropertyChange(). The value of the property doesn't |
| // matter, so HandleFreezeUpdatesPropertyChange() can be called directly in |
| // response to the property being added or deleted -- this method is just used |
| // by our c'tor to get the initial state. |
| void FetchAndApplyChromeFreezeUpdates(); |
| |
| // Check if the window has been shaped using the Shape extension and |
| // update its compositing actor accordingly. If the window is shaped, we |
| // hide its shadow if it has one. |
| void FetchAndApplyShape(); |
| |
| // Query the X server to see if this window is currently mapped or not. |
| // This should only be used for checking the state of an existing window |
| // at startup; use mapped() after that. |
| bool FetchMapState(); |
| |
| // Parse a _NET_WM_STATE message about this window, storing the requested |
| // state changes in |states_out|. The passed-in data is from the |
| // ClientMessage event. |
| void ParseWmStateMessage( |
| const long data[5], std::map<XAtom, bool>* states_out) const; |
| |
| // Set or unset _NET_WM_STATE values for this window. Updates our |
| // internal copy of the state and the window's _NET_WM_STATE property. |
| bool ChangeWmState(const std::map<XAtom, bool>& states); |
| |
| // Set or unset particular _CHROME_STATE values for this window (each |
| // atom's bool value states whether it should be added or removed). |
| // Other existing values in the property remain unchanged. |
| bool ChangeChromeState(const std::map<XAtom, bool>& states); |
| |
| // Give keyboard focus to the client window, using a WM_TAKE_FOCUS |
| // message if the client supports it or a SetInputFocus request |
| // otherwise. (Note that the client doesn't necessarily need to accept |
| // the focus if WM_TAKE_FOCUS is used; see ICCCM 4.1.7.) |
| // |
| // Most callers should call FocusManager::FocusWindow() instead of |
| // invoking this directly; FocusManager handles adding or removing button |
| // grabs for click-to-focus and updating the _NET_ACTIVE_WINDOW property. |
| bool TakeFocus(XTime timestamp); |
| |
| // If the window supports WM_DELETE_WINDOW messages, ask it to delete |
| // itself. Just does nothing and returns false otherwise. |
| bool SendDeleteRequest(XTime timestamp); |
| |
| // Send a _NET_WM_PING client message to the window so we can check that |
| // it's not frozen. |
| bool SendPing(XTime timestamp); |
| |
| // Add or remove a passive grab on button presses within this window. When |
| // (1-indexed) |button| is pressed, a _synchronous_ active pointer grab will |
| // be installed. Note that this means that no pointer events will be received |
| // until the pointer grab is manually removed using |
| // XConnection::UngrabPointer() -- this can be used to ensure that the client |
| // receives the initial click on its window when implementing click-to-focus |
| // behavior. |
| // |
| // Most callers should use FocusManager::UseClickToFocusForWindow(), |
| // which will handle all of this for them. |
| bool AddButtonGrab(int button); |
| bool RemoveButtonGrab(int button); |
| |
| // Get the largest possible size for this window smaller than or equal to |
| // the passed-in desired dimensions (while respecting any sizing hints it |
| // supplied via the WM_NORMAL_HINTS property). |
| void GetMaxSize(const Size& desired_size, Size* size_out) const; |
| |
| // Tell the X server to map or unmap this window. |
| bool MapClient(); |
| bool UnmapClient(); |
| |
| // Set the window's visibility and input policy. Once this method has been |
| // called, the Move() method (as opposed to MoveClient() / MoveComposited()) |
| // must be used to move the window. |
| void SetVisibility(Visibility visibility); |
| |
| // Start or stop updating the client window's position in response to calls to |
| // Move(). Disabling client window updates while moving the window repeatedly |
| // (e.g. if the user is dragging it around) can be useful to limit the number |
| // of requests sent to and ConfigureNotify events received from the X server. |
| // When updates are turned back on, the client window will be moved it its |
| // correct position. This method can only be used if SetVisibility() was |
| // previously called. |
| void SetUpdateClientPositionForMoves(bool update); |
| |
| // Move and/or resize the window to fill |bounds| over |anim_ms| milliseconds. |
| // At present, this is essentially the same as calling Move() and Resize() |
| // individually (although it also makes a weak effort to choose a smart |
| // |gravity| parameter for Resize() in the case where doing so can avoid |
| // jank). |
| void SetBounds(const Rect& bounds, int anim_ms); |
| |
| // Move the window to |origin| over |anim_ms| milliseconds. |
| // This method moves both the composited and client windows, but it can only |
| // be used if the window's visibility has been set via SetVisibility(). |
| // Use the individual MoveClient() and MoveComposited() methods otherwise. |
| void Move(const Point& origin, int anim_ms); |
| |
| // These methods are like Move(), but they move only the X or Y coordinate of |
| // the window, leaving the other coordinate (and any ongoing animation it may |
| // have) untouched. |
| void MoveX(int x, int anim_ms); |
| void MoveY(int y, int anim_ms); |
| |
| // Ask the X server to move or resize the client window. Also calls the |
| // corresponding SetClient*() method on success. Returns false on |
| // failure. |
| // This method is deprecated; use SetBounds() or Move() instead. |
| bool MoveClient(int x, int y); |
| |
| // Move the client window offscreen to prevent it from receiving input. |
| // This method is deprecated; use SetVisibility() instead. |
| bool MoveClientOffscreen(); |
| |
| // Move the client window to the same position as the composited window. |
| // This method is deprecated; use Move() or SetBounds() instead. |
| bool MoveClientToComposited(); |
| |
| // Center the client window over the passed-in window. |
| bool CenterClientOverWindow(Window* owner); |
| |
| // Resize the client window. A southeast gravity means that the |
| // bottom-right corner of the window will remain fixed while the |
| // upper-left corner will move to accomodate the new size. |
| bool Resize(const Size& new_size, Gravity gravity); |
| |
| // Stack the client window directly above or below another window. |
| // Use StackingManager to restack the X window and the actor simultaneously |
| // instead of calling this method. |
| bool StackClientAbove(XWindow sibling_xid); |
| bool StackClientBelow(XWindow sibling_xid); |
| |
| // Make various changes to the composited window (and its shadow). |
| // These methods are deprecated; use SetBounds(), Move(), and SetVisibility() |
| // instead. |
| void MoveComposited(int x, int y, int anim_ms); |
| void MoveCompositedX(int x, int anim_ms); |
| void MoveCompositedY(int y, int anim_ms); |
| void MoveCompositedToClient(); // no animation |
| void ShowComposited(); |
| void HideComposited(); |
| |
| // Set the composited window's opacity over |anim_ms| milliseconds. |
| // If SetVisibility() has been previously called, setting the opacity to 0 |
| // will also move the X window offscreen so it doesn't receive input (but note |
| // that setting the opacity of the composited window's container won't have |
| // this effect). |
| void SetCompositedOpacity(double opacity, int anim_ms); |
| |
| // Scale the composited window in the X and Y dimensions over |anim_ms| |
| // milliseconds. |scale_x| and |scale_y| must be greater than or equal to 0. |
| // If SetVisibility() has been previously called, scaling the window with any |
| // values other than (1.0, 1.0) will also move the X window offscreen so it |
| // doesn't receive input (but note that scaling the composited window's |
| // container won't have this effect). |
| void ScaleComposited(double scale_x, double scale_y, int anim_ms); |
| |
| // Create and return a pair of Animation objects that can be used to animate |
| // the window's X and Y positions. Ownership of the object is passed to the |
| // caller, who should pass it back via SetMoveCompositedAnimation() after |
| // adding additional keyframes. |
| // |
| // Note that the window's shadow isn't currently animated. |
| AnimationPair* CreateMoveCompositedAnimation(); |
| |
| // Use a pair of animations previously allocated with |
| // CreateMoveCompositedAnimation() to animate this window's position. |
| // Takes ownership of |animations|. |
| void SetMoveCompositedAnimation(AnimationPair* animations); |
| |
| // Create and apply an animation of the window's scale. |
| // See CreateMoveCompositedAnimation() and SetMoveCompositedAnimation(). |
| AnimationPair* CreateScaleCompositedAnimation(); |
| void SetScaleCompositedAnimation(AnimationPair* animations); |
| |
| // Handle us having sent a request to the X server to map this |
| // (non-override-redirect) window. We send a _NET_WM_SYNC_REQUEST |
| // message to the window and send a synthetic ConfigureNotify event, so |
| // that we'll be notified by the client when it's finished painting the |
| // window. |
| void HandleMapRequested(); |
| |
| // Handle a MapNotify event about this window. |
| // We throw away the old pixmap for the window and get the new one. |
| void HandleMapNotify(); |
| |
| void HandleUnmapNotify(); |
| |
| // This method is called when this window is redirected for compositing |
| // after it has been unredirected. The previously stored pixmap is no longer |
| // valid, so it updates the pixmap by calling ResetPixmap. The content of |
| // the root window is copied to the new pixmap, so that the new pixmap's |
| // uninitialized contents are not briefly visible. This method can only be |
| // called if this window's contents are currently painted on the entire root |
| // window at (0, 0). |
| void HandleRedirect(); |
| |
| // Handle a ConfigureNotify event about this window. |
| // We fetch a new pixmap for the window if its size has changed and |
| // update its composited position if it's an override-redirect window. |
| void HandleConfigureNotify(const Rect& bounds, XWindow above_xid); |
| |
| // Handle the window's contents being changed. |
| void HandleDamageNotify(const Rect& bounding_box); |
| |
| // Handle the _CHROME_FREEZE_UPDATES property getting set or unset on this |
| // window. See |updates_frozen_| for details. |
| void HandleFreezeUpdatesPropertyChange(bool frozen); |
| |
| // Handle the underlying X window being destroyed. If this method is |
| // invoked before destroying this Window object, a few |
| // compositing-related resources (actor, shadow, X pixmap) will be |
| // jettisoned via the returned DestroyedWindow object, ownership of which |
| // passes to the caller. |
| // |
| // Attempts to continue using the Window object after invoking this |
| // method will end in heartbreak -- almost every method will crash. Only |
| // call this when you're about to destroy the Window object. Just |
| // destroying the Window without calling this method first is fine if you |
| // have no desire to continue displaying the window's contents onscreen. |
| DestroyedWindow* HandleDestroyNotify(); |
| |
| // Enable drawing a drop shadow of a given type beneath this window. |
| // Note that even if this method is called, the shadow may not be visible |
| // (shadows aren't drawn for shaped windows, for instance) -- see |
| // UpdateShadowVisibility(). By default, we don't draw a shadow until |
| // this method is called. |
| void SetShadowType(Shadow::Type type); |
| |
| // Disable drawing a drop shadow beneath this window. |
| void DisableShadow(); |
| |
| // Change the opacity of the window's shadow. The shadow's opacity is |
| // multiplied by that of the window itself. |
| void SetShadowOpacity(double opacity, int anim_ms); |
| |
| // Stack the window directly above |actor| and its shadow directly above |
| // or below |shadow_actor| if supplied or below the window otherwise. If |
| // |actor| is NULL, the window's stacking isn't changed (but its shadow's |
| // still is). If |shadow_actor| is supplied, |stack_above_shadow_actor| |
| // determines whether the shadow will be stacked above or below it. |
| void StackCompositedAbove(Compositor::Actor* actor, |
| Compositor::Actor* shadow_actor, |
| bool stack_above_shadow_actor); |
| |
| // Stack the window directly below |actor| and its shadow directly above |
| // or below |shadow_actor| if supplied or below the window otherwise. If |
| // |actor| is NULL, the window's stacking isn't changed (but its shadow's |
| // still is). If |shadow_actor| is supplied, |stack_above_shadow_actor| |
| // determines whether the shadow will be stacked above or below it. |
| void StackCompositedBelow(Compositor::Actor* actor, |
| Compositor::Actor* shadow_actor, |
| bool stack_above_shadow_actor); |
| |
| // Return this window's topmost actor. |
| Compositor::Actor* GetTopActor(); |
| |
| // Return this window's bottom-most actor (either the window's shadow's |
| // group, or its actor itself if there's no shadow). This is useful for |
| // stacking another actor underneath this window. |
| Compositor::Actor* GetBottomActor(); |
| |
| // Store the client window's position and size in |rect|. |
| void CopyClientBoundsToRect(Rect* rect) const; |
| |
| // Handle notification that a Sync extension alarm (presumably |
| // |wm_sync_request_alarm_|) has triggered. |value| contains the |
| // triggering value of the counter being watched. |
| void HandleSyncAlarmNotify(XID alarm_id, int64_t value); |
| |
| // Send a synthetic ConfigureNotify event to the client containing the |
| // window's current position, size, etc. |
| void SendSyntheticConfigureNotify(); |
| |
| // Position to which we move X windows to prevent them from receiving input. |
| static const int kOffscreenX; |
| static const int kOffscreenY; |
| |
| private: |
| friend class BasicWindowManagerTest; |
| |
| FRIEND_TEST(FocusManagerTest, Modality); // sets |wm_state_modal_| |
| FRIEND_TEST(WindowTest, SyncRequest); |
| FRIEND_TEST(WindowTest, DeferFetchingPixmapUntilPainted); |
| FRIEND_TEST(WindowTest, FreezeUpdates); |
| FRIEND_TEST(WindowTest, AvoidMovingActorDuringResize); |
| FRIEND_TEST(WindowManagerTest, VideoTimeProperty); |
| FRIEND_TEST(WindowManagerTest, HandleLateSyncRequestCounter); |
| |
| // Minimum dimensions and rate per second for damage events at which we |
| // conclude that a video is currently playing in this window. |
| static const int kVideoMinWidth; |
| static const int kVideoMinHeight; |
| static const int kVideoMinFramerate; |
| |
| // Dimensions in which the actor should be moved by UpdateActorPosition(). |
| enum MoveDimensions { |
| MOVE_DIMENSIONS_X_AND_Y = 0, |
| MOVE_DIMENSIONS_X_ONLY, |
| MOVE_DIMENSIONS_Y_ONLY, |
| }; |
| |
| // Are the X window's contents currently in a state where we're able to fetch |
| // them as a new pixmap? |
| bool able_to_reset_pixmap() const { |
| return client_has_redrawn_after_last_resize_ && !updates_frozen_; |
| } |
| |
| // Should the X (a.k.a. "client") window be onscreen? |
| // Without support in X11 for transforming input events, scaled windows can't |
| // receive input. |
| bool x_window_should_be_onscreen() const { |
| return visibility_ == VISIBILITY_SHOWN && |
| composited_size() == client_size() && |
| composited_opacity_ > 0.0; |
| } |
| |
| |
| // Is the entirety of the client window currently offscreen? |
| bool IsClientWindowOffscreen() const; |
| |
| // Helper method for ParseWmStateMessage() and ChangeWmState(). Given an |
| // action from a _NET_WM_STATE message (i.e. the XClientMessageEvent's |
| // data.l[0] field), updates |value| accordingly. |
| void SetWmStateInternal(int action, bool* value) const; |
| |
| // Ask the X server to move the client window to |origin|, calling |
| // SaveClientPosition() on success. Returns false on failure. |
| bool MoveClientInternal(const Point& origin); |
| |
| // Update |composited_origin_|. If we're not in the middle of a resize, we |
| // also call UpdateActorPosition() to move the actor; otherwise the actor will |
| // be updated later after we've fetched a new pixmap. Depending on the value |
| // of |dimensions|, either the X coordinate, Y coordinate, or both from |
| // |origin| may be used. |
| void MoveCompositedInternal(const Point& origin, |
| MoveDimensions dimensions, |
| int anim_ms); |
| |
| // Update the client window's position appropriately based on the current |
| // visibility setting. This can only be invoked if the visibility has been |
| // set (i.e. it isn't equal to VISIBILITY_UNSET). |
| void UpdateClientWindowPosition(); |
| |
| // Move |actor_| to the position in |composited_origin_| over |anim_ms|. |
| // |dimensions| can be used to limit the dimension over which the actor is |
| // moved to just X or Y. |
| // |
| // Way more background than you want to know: resizing a client window can be |
| // tricky for compositing window managers. Suppose that we have a 20x20 |
| // window located at (10, 10) and we want to make it bigger so that its |
| // upper-left corner goes to (5, 10) while the right edge remains fixed, |
| // resulting in a 25x20 window. Resize() asks the X server to atomically move |
| // and resize the window to the new bounds, but the window can't be drawn at |
| // the new size until the client has received the ConfigureNotify event and |
| // finished painting the new pixmap. If we move the actor to (5, 10) |
| // immediately and then update its pixmap later, the window will initially |
| // appear to jump to the left by 5 pixels; once we get the new pixmap, the |
| // right edge will expand by 5 pixels. |
| // |
| // To avoid this jank, we update |composited_origin_| immediately in Resize() |
| // if the window's origin moved due to the resize gravity but hold off on |
| // actually moving the actor until its size changes. Similarly, methods like |
| // Move() may not actually move the actor to the requested position |
| // immediately -- if we're waiting for the pixmap to be resized, we defer |
| // updating the actor until we have the resized pixmap. |
| void UpdateActorPosition(MoveDimensions dimensions, int anim_ms); |
| |
| // Update the window's _NET_WM_STATE property based on the current values |
| // of the |wm_state_*| members. |
| bool UpdateWmStateProperty(); |
| |
| // Update the window's _CHROME_STATE property based on the current |
| // contents of |chrome_state_atoms_|. |
| bool UpdateChromeStateProperty(); |
| |
| // Destroys |wm_sync_request_alarm_| if non-NULL, unregisters our |
| // interest in it in the WindowManager, and resets |
| // |client_has_redrawn_after_last_resize_| to true. |
| void DestroyWmSyncRequestAlarm(); |
| |
| // Free |pixmap_|, store a new offscreen pixmap containing the window's |
| // contents in it, and notify |actor_| that the pixmap has changed. |
| void ResetPixmap(); |
| |
| // Update the visibility of |shadow_| if it's non-NULL. This window's |
| // shadow can be enabled or disabled via SetShouldUseShadow(), but there |
| // are still other reasons that we may not draw the shadow (e.g. the |
| // window is shaped or not yet mapped). This method is called when |
| // various states that can prevent us from drawing the shadow are changed. |
| void UpdateShadowVisibility(); |
| |
| // If the client supports _NET_WM_SYNC_REQUEST, increment |
| // |current_wm_sync_num_| and send the client a message telling it to |
| // update the counter after it's seen the ConfigureNotify and redrawn its |
| // contents. |
| void SendWmSyncRequestMessage(); |
| |
| // Update debugging information shown onscreen in response to a damage event |
| // (if WindowManager::damage_debugging_enabled() is true). |
| void UpdateDamageDebugging(const Rect& bounding_box); |
| |
| XWindow xid_; |
| std::string xid_str_; // hex for debugging |
| WindowManager* wm_; |
| scoped_ptr<Compositor::TexturePixmapActor> actor_; |
| |
| // This contains a shadow if SetShouldUseShadow(true) has been called and |
| // is NULL otherwise. |
| scoped_ptr<Shadow> shadow_; |
| |
| // The XID that this window says it's transient for. Note that the |
| // client can arbitrarily supply an ID here; the window doesn't |
| // necessarily exist. A good general practice may be to examine this |
| // value when the window is mapped and ignore any changes after that. |
| XWindow transient_for_xid_; |
| |
| // Was override-redirect set when the window was originally created? |
| bool override_redirect_; |
| |
| // Is the client window currently mapped? This is only updated when the |
| // Window object is first created and when a MapNotify or UnmapNotify |
| // event is received (dependent on the receiver calling set_mapped() |
| // appropriately), so e.g. a call to MapClient() will not be immediately |
| // reflected in this variable. |
| bool mapped_; |
| |
| // Is the window shaped (using the Shape extension)? |
| bool shaped_; |
| |
| // Client-supplied window type. |
| chromeos::WmIpcWindowType type_; |
| |
| // Parameters associated with |type_|. See chromeos::WmIpcWindowType for |
| // details. |
| std::vector<int> type_params_; |
| |
| Visibility visibility_; |
| |
| // Should we update the client window's position in response to calls to |
| // Move()? |
| bool update_client_position_for_moves_; |
| |
| // Position and size of the client window. |
| Rect client_bounds_; |
| |
| // Bit depth of the client window. |
| int client_depth_; |
| |
| // Client-requested opacity (via _NET_WM_WINDOW_OPACITY). |
| double client_opacity_; |
| |
| bool composited_shown_; |
| Point composited_origin_; |
| double composited_scale_x_; |
| double composited_scale_y_; |
| double composited_opacity_; |
| |
| // Current opacity requested for the window's shadow. |
| double shadow_opacity_; |
| |
| std::string title_; |
| |
| // Information from the WM_NORMAL_HINTS property. |
| XConnection::SizeHints size_hints_; |
| |
| // Does the window have a WM_PROTOCOLS property claiming that it supports |
| // WM_TAKE_FOCUS or WM_DELETE_WINDOW messages? |
| bool supports_wm_take_focus_; |
| bool supports_wm_delete_window_; |
| bool supports_wm_ping_; |
| |
| // EWMH window state, as set by _NET_WM_STATE client messages and exposed |
| // in the window's _NET_WM_STATE property. |
| // TODO: Just store these in a set like we do for _CHROME_STATE below. |
| bool wm_state_fullscreen_; |
| bool wm_state_maximized_horz_; |
| bool wm_state_maximized_vert_; |
| bool wm_state_modal_; |
| |
| // Is this window marked urgent, per the ICCCM UrgencyHint flag in its |
| // WM_HINTS property? |
| bool wm_hint_urgent_; |
| |
| // EWMH window types from the window's _NET_WM_WINDOW_TYPE property, in |
| // the order in which they appear (which is the window's preference for |
| // which type should be used). |
| std::vector<XAtom> wm_window_type_xatoms_; |
| |
| // Chrome window state, as exposed in the window's _CHROME_STATE |
| // property. |
| std::set<XAtom> chrome_state_xatoms_; |
| |
| // Local bounds of the window's status area (clock, battery, etc.) as reported |
| // by the _CHROME_STATUS_BOUNDS property. |
| Rect status_bounds_; |
| |
| // Damage object used to track changes to |xid_|. |
| XID damage_; |
| |
| // Offscreen pixmap containing the window's redirected contents. |
| XID pixmap_; |
| |
| // Do we need to move |actor_| to |composited_origin_| the next time that we |
| // get a pixmap that's the same size as the underlying X window? |
| bool need_to_update_actor_position_; |
| |
| // Do we need to fetch a new pixmap to get at the X window's contents? |
| // This happens when the window is first mapped, or resized, or unredirected |
| // (in the X Composite Extension sense) and then redirected again. |
| bool need_to_reset_pixmap_; |
| |
| // XSync counter ID from the window's _NET_WM_SYNC_REQUEST_COUNTER |
| // property, or 0 if the window doesn't support _NET_WM_SYNC_REQUEST. |
| XID wm_sync_request_alarm_; |
| |
| // Most-recent update request number that we've sent to the window before |
| // resizing it as part of _NET_WM_SYNC_REQUEST. |
| int64_t current_wm_sync_num_; |
| |
| // Has the client indicated that it's redrawn the window after the last |
| // time that we resized it? (If not, we're currently waiting for the |
| // window to update |wm_sync_request_counter_| to match |
| // |current_wm_sync_num_|.) We also leave this at true if the client |
| // doesn't support _NET_WM_SYNC_REQUEST. |
| bool client_has_redrawn_after_last_resize_; |
| |
| // Is the _CHROME_FREEZE_UPDATES property currently set on this window? |
| // |
| // The client can set this to indicate that the WM should temporarily refrain |
| // from refetching the window's pixmap, to prevent a newly-mapped window from |
| // being shown until it's been painted (i.e. set the property, map the window, |
| // paint it in response to the expose event, and then unset the property). |
| // _NET_WM_SYNC_REQUEST could theoretically be used for this (for |
| // non-override-redirect windows only), but we've run into problems; see |
| // http://crosbug.com/11514. |
| // |
| // This is a partial implementation of the _NET_WM_FREEZE_UPDATES property |
| // proposed by Owen Taylor in |
| // http://mail.gnome.org/archives/wm-spec-list/2009-June/msg00002.html. Note |
| // that unlike the proposed version, our property doesn't prevent the window |
| // manager from rebinding the texture in response to damage events. This just |
| // hasn't been implemented because it makes the code more complicated and we |
| // don't need it -- Chrome uses double-buffering. |
| bool updates_frozen_; |
| |
| // Hostname of the system on which the client is running, as specified in |
| // the WM_CLIENT_MACHINE property. |
| std::string client_hostname_; |
| |
| // The client's PID as specified in the _NET_WM_PID property, or -1 if |
| // unknown. |
| int client_pid_; |
| |
| // Number of "video-sized" or larger damage events that we've seen for |
| // this window during the second beginning at |video_damage_start_time_|. |
| // We use this as a rough heuristic to try to detect when the user is |
| // watching a video. |
| int num_video_damage_events_; |
| time_t video_damage_start_time_; |
| |
| // Group containing actors that we display to visualize damage events for |
| // this window. Stacked directly above |actor_| (but lazily initialized and |
| // NULL until the first time we need it). |
| scoped_ptr<Compositor::ContainerActor> damage_debug_group_; |
| |
| // Actors in |damage_debug_group_|. We add new ones to the deque as needed |
| // and start recycling them after hitting a limit. |
| std::deque<std::tr1::shared_ptr<Compositor::ColoredBoxActor> > |
| damage_debug_actors_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Window); |
| }; |
| |
| // We sometimes want to continue displaying a window's contents onscreen |
| // even after receiving a DestroyNotify event indicating that the |
| // underlying X window was closed. DestroyedWindow contains a subset of |
| // compositing-related resources that have been released from an |
| // about-to-be-deleted Window object. |
| class DestroyedWindow { |
| public: |
| DestroyedWindow(WindowManager* wm, |
| XWindow xid, |
| Compositor::TexturePixmapActor* actor, |
| Shadow* shadow, |
| XID pixmap); |
| ~DestroyedWindow(); |
| |
| WindowManager* wm() { return wm_; } |
| Compositor::TexturePixmapActor* actor() { return actor_.get(); } |
| Shadow* shadow() { return shadow_.get(); } |
| |
| private: |
| WindowManager* wm_; // not owned |
| |
| // Compositing actor being used to display |pixmap_|. This object |
| // initially uses the same position, scaling, stacking, opacity, etc. |
| // that it had when owned by the Window. |
| scoped_ptr<Compositor::TexturePixmapActor> actor_; |
| |
| // Drop shadow that was set for the window, or NULL if no shadow was set. |
| // Note that changes made to |actor_| will need to be manually applied to |
| // |shadow_| as well. |
| scoped_ptr<Shadow> shadow_; |
| |
| // X pixmap displayed by |actor_|; freed in our destructor. |
| // TODO: Can this be freed when the Window object is destroyed, or even |
| // earlier? The actor is displaying a GL texture bound to a GLX pixmap |
| // that was created from this X pixmap. |
| XID pixmap_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DestroyedWindow); |
| }; |
| |
| } // namespace window_manager |
| |
| #endif // WINDOW_MANAGER_WINDOW_H_ |