File: background_manager.hpp

package info (click to toggle)
polybar 3.7.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,108 kB
  • sloc: cpp: 30,424; python: 3,750; sh: 284; makefile: 83
file content (155 lines) | stat: -rw-r--r-- 4,363 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#pragma once

#include <memory>
#include <vector>

#include "common.hpp"
#include "events/signal_fwd.hpp"
#include "events/signal_receiver.hpp"
#include "x11/extensions/fwd.hpp"
#include "x11/types.hpp"

POLYBAR_NS

class logger;

namespace cairo {
  class surface;
  class xcb_surface;
} // namespace cairo

class bg_slice {
 public:
  ~bg_slice();
  // copying bg_slices is not allowed
  bg_slice(const bg_slice&) = delete;
  bg_slice& operator=(const bg_slice&) = delete;

  cairo::surface* get_surface() const;

  void clear();
  void copy(xcb_pixmap_t root_pixmap, int depth, xcb_rectangle_t geom, xcb_visualtype_t* visual);

 private:
  bg_slice(connection& conn, const logger& log, xcb_rectangle_t rect, xcb_window_t window);

  connection& m_connection;
  const logger& m_log;

  /**
   * Area covered by this slice
   *
   * Area is relative to given window
   */
  xcb_rectangle_t m_rect{0, 0, 0U, 0U};
  xcb_window_t m_window;

  /**
   * Cache for the root window background at this slice's position
   */
  xcb_pixmap_t m_pixmap{XCB_NONE};
  unique_ptr<cairo::xcb_surface> m_surface;
  xcb_gcontext_t m_gcontext{XCB_NONE};
  int m_depth{0};

  void ensure_resources(int depth, xcb_visualtype_t* visual);
  void allocate_resources(xcb_visualtype_t* visual);
  void free_resources();

  friend class background_manager;
};

/**
 * @brief Class to keep track of the desktop background used to support pseudo-transparency
 *
 * For pseudo-transparency that bar needs access to the desktop background.
 * We only need to store the slice of the background image which is covered by the bar window,
 * so this class takes a rectangle that limits what part of the background is stored.
 */
class background_manager : public signal_receiver<SIGN_PRIORITY_SCREEN, signals::ui::update_geometry>,
                           public xpp::event::sink<evt::property_notify> {
 public:
  using make_type = background_manager&;
  static make_type make();

  /**
   * Initializes a new background_manager that by default does not observe anything.
   *
   * To observe a slice of the background you need to call background_manager::activate.
   */
  explicit background_manager(connection& conn, signal_emitter& sig, const logger& log);
  ~background_manager();

  /**
   * Starts observing a rectangular slice of the desktop background.
   *
   * After calling this function, you can obtain the current slice of the desktop background
   * by calling get_surface on the returned bg_slice object.
   * Whenever the background slice changes (for example, due to bar position changes or because
   * the user changed the desktop background) the class emits a signals::ui::update_background event.
   *
   * You should only call this function once and then re-use the returned bg_slice because the bg_slice
   * caches the background. If you don't need the background anymore, destroy the shared_ptr to free up
   * resources.
   *
   * @param rect Slice of the background to observe (coordinates relative to window).
   * @param window Coordinates are interpreted relative to this window
   */
  std::shared_ptr<bg_slice> observe(xcb_rectangle_t rect, xcb_window_t window);

  void handle(const evt::property_notify& evt) override;
  bool on(const signals::ui::update_geometry&) override;

 private:
  void activate();
  void deactivate();

  void attach();
  void detach();
  /**
   * True if we are currently attached as a listener for desktop background changes
   */
  bool m_attached{false};

  // references to standard components
  connection& m_connection;
  signal_emitter& m_sig;
  const logger& m_log;

  /**
   * List of slices that need to be filled with the desktop background
   */
  std::vector<std::weak_ptr<bg_slice>> m_slices;

  void allocate_resources();
  void free_resources();
  void on_background_change();

  void update_slice(bg_slice& slice);

  bool has_pixmap() const;
  void ensure_pixmap();
  void load_pixmap();
  void clear_pixmap();

  /**
   * The loaded root pixmap
   */
  xcb_pixmap_t m_pixmap{XCB_NONE};
  int m_pixmap_depth{0};
  xcb_rectangle_t m_pixmap_geom{0, 0, 0, 0};

  /**
   * Tracks whether we were able to load a pixmap.
   */
  bool m_pixmap_load_failed{false};

  /**
   * Visual matching the root pixmap's depth.
   *
   * Only valid if m_pixmap is set
   */
  xcb_visualtype_t* m_visual{nullptr};
};

POLYBAR_NS_END