src/util/area.h (raw)
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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
/************************************************************************** * Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr) * **************************************************************************/ #ifndef AREA_H #define AREA_H #include <glib.h> #include <X11/Xlib.h> #include <cairo.h> #include <cairo-xlib.h> #include "color.h" #include "gradient.h" // DATA ORGANISATION // // Areas in tint2 are similar to widgets in a GUI. // All graphical objects (panel, taskbar, task, systray, clock, ...) inherit the abstract class Area. // This class 'Area' stores data about the background, border, size, position, padding and the child areas. // Inheritance is simulated by having an Area member as the first member of each object (thus &object == &area). // // tint2 uses multiple panels, one per monitor. Each panel has an area containing the children objects in a tree of // areas. The level in the tree gives the z-order: child areas are always displayed on top of their parents. // // // LAYOUT // // Sibling areas never overlap. // // The position of an Area (posx, posy) is relative to the window (i.e. absolute) and // is computed based on a simple box model: // * parent position + parent padding + sum of the sizes of the previous siblings and spacing // // The size of an Area is: // * SIZE_BY_CONTENT objects: // * fixed and set by the Area // * childred are resized before the parent // * if a child size has changed then the parent is resized // * SIZE_BY_LAYOUT objects: // * expandable and computed as the total size of the parent - padding - // the size of the fixed sized siblings - spacing and divided by the number of expandable siblings // * the parent is resized before the children // // // RENDERING // // Redrawing an object (like the clock) could come from an 'external event' (date change) // or from a 'layout event' (position change). // // // WIDGET LIFECYCLE // // Each widget that occurs once per panel is defined as a struct (e.g. Clock) which is stored as a member of Panel. // Widgets that can occur more than once should be stored as an array, still as a member of Panel. // // There is a special Panel instance called 'panel_config' which stores the config options and the state variables // of the widgets (however some config options are stored as global variables by the widgets). // // Tint2 maintains an array of Panel instances, one for each monitor. These contain the actual Areas that are used to // render the panels on screen, interact with user input etc. // Each Panel is initialized as a raw copy (memcpy, see init_panel()) of panel_config. // // Normally, widgets should implement the following functions: // // * void default_widget(); // // Called before the config is read and panel_config/panels are created. // Afterwards, the config parsing code creates the widget/widget array in panel_config and // populates the configuration fields. // If the widget uses global variables to store config options or other state variables, they should be initialized // here (e.g. with zero, NULL etc). // // * void init_widget(); // // Called after the config is read and panel_config is populated, but before panels are created. // Initializes the state of the widget in panel_config. // If the widget uses global variables to store config options or other state variables which depend on the config // options but not on the panel instance, they should be initialized here. // panel_config.panel_items can be used to determine which backend items are enabled. // // * void init_widget_panel(void *panel); // // Called after each on-screen panel is created, with a pointer to the panel. // Completes the initialization of the widget. // At this point the widget Area has not been added yet to the GUI tree, but it will be added right afterwards. // // * void cleanup_widget(); // // Called just before the panels are destroyed. Afterwards, tint2 exits or restarts and reads the config again. // Must releases all resources. // The widget itself should not be freed by this function, only its members or global variables that were set. // The widget is freed by the Area tree cleanup function (remove_area). // // * void draw_widget(void *obj, cairo_t *c); // // Called on draw, obj = pointer to the widget instance from the panel that is redrawn. // The Area's _draw_foreground member must point to this function. // // * int resize_widget(void *obj); // // Called on resize, obj = pointer to the front-end Execp item. // Returns 1 if the new size is different than the previous size. // The Area's _resize member must point to this function. // // * void widget_action(void *obj, int button); // // Called on mouse click event. // // * void widget_on_change_layout(void *obj); // // Implemented only to override the default layout algorithm for this widget. // For example, if this widget is a cell in a table, its position and size should be computed here. // The Area's _on_change_layout member must point to this function. // // * char* widget_get_tooltip_text(void *obj); // // Returns a copy of the tooltip to be displayed for this widget. // The caller takes ownership of the pointer. // The Area's _get_tooltip_text member must point to this function. typedef enum BorderMask { BORDER_TOP = 1 << 0, BORDER_BOTTOM = 1 << 1, BORDER_LEFT = 1 << 2, BORDER_RIGHT = 1 << 3 } BorderMask; #define BORDER_ALL (BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT) typedef struct Border { // It's essential that the first member is color Color color; // Width in pixels int width; // Corner radius int radius; // Mask: bitwise OR of BorderMask int mask; } Border; typedef struct Background { // Normal state Color fill_color; Border border; // On mouse hover Color fill_color_hover; Color border_color_hover; // On mouse press Color fill_color_pressed; Color border_color_pressed; } Background; typedef enum Layout { LAYOUT_DYNAMIC, LAYOUT_FIXED, } Layout; typedef enum Alignment { ALIGN_LEFT = 0, ALIGN_CENTER = 1, ALIGN_RIGHT = 2, } Alignment; typedef enum MouseState { MOUSE_NORMAL = 0, MOUSE_OVER = 1, MOUSE_DOWN = 2, MOUSE_STATE_COUNT } MouseState; struct Panel; typedef struct Area { // Position relative to the panel window int posx, posy; // Size, including borders int width, height; Background *bg; // Each element is a pointer to a GradientClass (list can be empty), no ownership GList *gradients; // Each element is a GradientInstance attached to this Area (list can be empty) GList *gradient_instances; // Each element is a GradientInstance that depends on this Area's geometry (position or size) GList *dependent_gradients; // List of children, each one a pointer to Area GList *children; // Pointer to the parent Area or NULL void *parent; // Pointer to the Panel that contains this Area void *panel; Layout size_mode; Alignment alignment; gboolean has_mouse_over_effect; gboolean has_mouse_press_effect; // TODO padding/spacing is a clusterfuck // paddingxlr = padding // paddingy = vertical padding, sometimes // paddingx = spacing int paddingxlr, paddingx, paddingy; MouseState mouse_state; // Set to non-zero if the Area is visible. An object may exist but stay hidden. gboolean on_screen; // Set to non-zero if the size of the Area has to be recalculated. gboolean resize_needed; // Set to non-zero if the Area has to be redrawn. // Do not set this directly; use schedule_redraw() instead. gboolean _redraw_needed; // Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called gboolean _changed; // This is the pixmap on which the Area is rendered. Render to it directly if needed. Pixmap pix; Pixmap pix_by_state[MOUSE_STATE_COUNT]; char name[32]; // Callbacks // Called on draw before any drawing takes place, obj = pointer to the Area void (*_clear)(void *obj); // Called on draw, obj = pointer to the Area void (*_draw_foreground)(void *obj, cairo_t *c); // Called on resize, obj = pointer to the Area // Returns 1 if the new size is different than the previous size. gboolean (*_resize)(void *obj); // Called before resize, obj = pointer to the Area // Returns the desired size of the Area int (*_compute_desired_size)(void *obj); // Implemented only to override the default layout algorithm for this widget. // For example, if this widget is a cell in a table, its position and size should be computed here. void (*_on_change_layout)(void *obj); // Returns a copy of the tooltip to be displayed for this widget. // The caller takes ownership of the pointer. char *(*_get_tooltip_text)(void *obj); // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. // Leave this to NULL to use a default implementation. gboolean (*_is_under_mouse)(void *obj, int x, int y); // Prints the geometry of the object on stderr, with left indentation of indent spaces. void (*_dump_geometry)(void *obj, int indent); } Area; // Initializes the Background member to default values. void init_background(Background *bg); // Layout // Called on startup to initialize the positions of all Areas in the Area tree. // Parameters: // * obj: pointer to Area // * offset: offset in pixels from left/top, relative to the window void initialize_positions(void *obj, int offset); // Relayouts the Area and its children. Normally called on the root of the tree (i.e. the Panel). void relayout(Area *a); // Distributes the Area's size to its children, repositioning them as needed. // If maximum_size > 0, it is an upper limit for the child size. int relayout_with_constraint(Area *a, int maximum_size); int compute_desired_size(Area *a); int left_border_width(Area *a); int right_border_width(Area *a); int left_right_border_width(Area *a); int top_border_width(Area *a); int bottom_border_width(Area *a); int top_bottom_border_width(Area *a); int left_bg_border_width(Background *bg); int right_bg_border_width(Background *bg); int top_bg_border_width(Background *bg); int bottom_bg_border_width(Background *bg); int left_right_bg_border_width(Background *bg); int top_bottom_bg_border_width(Background *bg); // Rendering // Sets the redraw_needed flag on the area and its descendants void schedule_redraw(Area *a); // Recreates the Area pixmap and draws the background and the foreground void draw(Area *a); // Draws the background of the Area void draw_background(Area *a, cairo_t *c); // Explores the entire Area subtree (only if the on_screen flag set) // and draws the areas with the redraw_needed flag set void draw_tree(Area *a); // Clears the on_screen flag, sets the size to zero and triggers a parent resize void hide(Area *a); // Sets the on_screen flag and triggers a parent and area resize void show(Area *a); // Area tree void add_area(Area *a, Area *parent); void remove_area(Area *a); void free_area(Area *a); // Mouse events // Returns the area under the mouse for the given x, y mouse coordinates relative to the window. // If no area is found, returns the root. Area *find_area_under_mouse(void *root, int x, int y); // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. gboolean area_is_under_mouse(void *obj, int x, int y); // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. // The Area will also handle clicks on the border of its ancestors, including the panel. // Useful so that a click at the edge of the screen is still handled by task buttons etc., even if technically // they are outside the drawing area of the button. gboolean full_width_area_is_under_mouse(void *obj, int x, int y); void instantiate_area_gradients(Area *area); void free_area_gradient_instances(Area *area); void area_dump_geometry(Area *area, int indent); void mouse_over(Area *area, int pressed); void mouse_out(); void update_gradient(GradientInstance *gi); void update_dependent_gradients(Area *a); #endif |