1 /************************************************************************** 2 * Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr) 3 * 4 **************************************************************************/ 5 6 #ifndef AREA_H 7 #define AREA_H 8 9 #include <glib.h> 10 #include <X11/Xlib.h> 11 #include <cairo.h> 12 #include <cairo-xlib.h> 13 14 #include "color.h" 15 #include "gradient.h" 16 17 // DATA ORGANISATION 18 // 19 // Areas in tint2 are similar to widgets in a GUI. 20 // All graphical objects (panel, taskbar, task, systray, clock, ...) inherit the abstract class Area. 21 // This class 'Area' stores data about the background, border, size, position, padding and the child areas. 22 // Inheritance is simulated by having an Area member as the first member of each object (thus &object == &area). 23 // 24 // tint2 uses multiple panels, one per monitor. Each panel has an area containing the children objects in a tree of 25 // areas. The level in the tree gives the z-order: child areas are always displayed on top of their parents. 26 // 27 // 28 // LAYOUT 29 // 30 // Sibling areas never overlap. 31 // 32 // The position of an Area (posx, posy) is relative to the window (i.e. absolute) and 33 // is computed based on a simple box model: 34 // * parent position + parent padding + sum of the sizes of the previous siblings and spacing 35 // 36 // The size of an Area is: 37 // * SIZE_BY_CONTENT objects: 38 // * fixed and set by the Area 39 // * childred are resized before the parent 40 // * if a child size has changed then the parent is resized 41 // * SIZE_BY_LAYOUT objects: 42 // * expandable and computed as the total size of the parent - padding - 43 // the size of the fixed sized siblings - spacing and divided by the number of expandable siblings 44 // * the parent is resized before the children 45 // 46 // 47 // RENDERING 48 // 49 // Redrawing an object (like the clock) could come from an 'external event' (date change) 50 // or from a 'layout event' (position change). 51 // 52 // 53 // WIDGET LIFECYCLE 54 // 55 // Each widget that occurs once per panel is defined as a struct (e.g. Clock) which is stored as a member of Panel. 56 // Widgets that can occur more than once should be stored as an array, still as a member of Panel. 57 // 58 // There is a special Panel instance called 'panel_config' which stores the config options and the state variables 59 // of the widgets (however some config options are stored as global variables by the widgets). 60 // 61 // Tint2 maintains an array of Panel instances, one for each monitor. These contain the actual Areas that are used to 62 // render the panels on screen, interact with user input etc. 63 // Each Panel is initialized as a raw copy (memcpy, see init_panel()) of panel_config. 64 // 65 // Normally, widgets should implement the following functions: 66 // 67 // * void default_widget(); 68 // 69 // Called before the config is read and panel_config/panels are created. 70 // Afterwards, the config parsing code creates the widget/widget array in panel_config and 71 // populates the configuration fields. 72 // If the widget uses global variables to store config options or other state variables, they should be initialized 73 // here (e.g. with zero, NULL etc). 74 // 75 // * void init_widget(); 76 // 77 // Called after the config is read and panel_config is populated, but before panels are created. 78 // Initializes the state of the widget in panel_config. 79 // If the widget uses global variables to store config options or other state variables which depend on the config 80 // options but not on the panel instance, they should be initialized here. 81 // panel_config.panel_items can be used to determine which backend items are enabled. 82 // 83 // * void init_widget_panel(void *panel); 84 // 85 // Called after each on-screen panel is created, with a pointer to the panel. 86 // Completes the initialization of the widget. 87 // At this point the widget Area has not been added yet to the GUI tree, but it will be added right afterwards. 88 // 89 // * void cleanup_widget(); 90 // 91 // Called just before the panels are destroyed. Afterwards, tint2 exits or restarts and reads the config again. 92 // Must releases all resources. 93 // The widget itself should not be freed by this function, only its members or global variables that were set. 94 // The widget is freed by the Area tree cleanup function (remove_area). 95 // 96 // * void draw_widget(void *obj, cairo_t *c); 97 // 98 // Called on draw, obj = pointer to the widget instance from the panel that is redrawn. 99 // The Area's _draw_foreground member must point to this function. 100 // 101 // * int resize_widget(void *obj); 102 // 103 // Called on resize, obj = pointer to the front-end Execp item. 104 // Returns 1 if the new size is different than the previous size. 105 // The Area's _resize member must point to this function. 106 // 107 // * void widget_action(void *obj, int button); 108 // 109 // Called on mouse click event. 110 // 111 // * void widget_on_change_layout(void *obj); 112 // 113 // Implemented only to override the default layout algorithm for this widget. 114 // For example, if this widget is a cell in a table, its position and size should be computed here. 115 // The Area's _on_change_layout member must point to this function. 116 // 117 // * char* widget_get_tooltip_text(void *obj); 118 // 119 // Returns a copy of the tooltip to be displayed for this widget. 120 // The caller takes ownership of the pointer. 121 // The Area's _get_tooltip_text member must point to this function. 122 123 typedef enum BorderMask { 124 BORDER_TOP = 1 << 0, 125 BORDER_BOTTOM = 1 << 1, 126 BORDER_LEFT = 1 << 2, 127 BORDER_RIGHT = 1 << 3 128 } BorderMask; 129 130 #define BORDER_ALL (BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT) 131 132 typedef struct Border { 133 // It's essential that the first member is color 134 Color color; 135 // Width in pixels 136 int width; 137 // Corner radius 138 int radius; 139 // Mask: bitwise OR of BorderMask 140 int mask; 141 } Border; 142 143 typedef enum MouseState { MOUSE_NORMAL = 0, MOUSE_OVER = 1, MOUSE_DOWN = 2, MOUSE_STATE_COUNT } MouseState; 144 145 typedef struct Background { 146 // Normal state 147 Color fill_color; 148 Border border; 149 // On mouse hover 150 Color fill_color_hover; 151 Color border_color_hover; 152 // On mouse press 153 Color fill_color_pressed; 154 Color border_color_pressed; 155 // Pointer to a GradientClass or NULL, no ownership 156 GradientClass *gradients[MOUSE_STATE_COUNT]; 157 double fill_content_tint_weight; 158 double border_content_tint_weight; 159 } Background; 160 161 typedef enum Layout { 162 LAYOUT_DYNAMIC, 163 LAYOUT_FIXED, 164 } Layout; 165 166 typedef enum Alignment { 167 ALIGN_LEFT = 0, 168 ALIGN_CENTER = 1, 169 ALIGN_RIGHT = 2, 170 } Alignment; 171 172 struct Panel; 173 174 typedef struct Area { 175 // Position relative to the panel window 176 int posx, posy; 177 // Size, including borders 178 int width, height; 179 int old_width, old_height; 180 Background *bg; 181 // Each element is a GradientInstance attached to this Area (list can be empty) 182 GList *gradient_instances_by_state[MOUSE_STATE_COUNT]; 183 // Each element is a GradientInstance that depends on this Area's geometry (position or size) 184 GList *dependent_gradients; 185 // List of children, each one a pointer to Area 186 GList *children; 187 // Pointer to the parent Area or NULL 188 void *parent; 189 // Pointer to the Panel that contains this Area 190 void *panel; 191 Layout size_mode; 192 Alignment alignment; 193 gboolean has_mouse_over_effect; 194 gboolean has_mouse_press_effect; 195 // TODO padding/spacing is a clusterfuck 196 // paddingxlr = padding 197 // paddingy = vertical padding, sometimes 198 // paddingx = spacing 199 int paddingxlr, paddingx, paddingy; 200 MouseState mouse_state; 201 // Set to non-zero if the Area is visible. An object may exist but stay hidden. 202 gboolean on_screen; 203 // Set to non-zero if the size of the Area has to be recalculated. 204 gboolean resize_needed; 205 // Set to non-zero if the Area has to be redrawn. 206 // Do not set this directly; use schedule_redraw() instead. 207 gboolean _redraw_needed; 208 // Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called 209 gboolean _changed; 210 // This is the pixmap on which the Area is rendered. Render to it directly if needed. 211 Pixmap pix; 212 Pixmap pix_by_state[MOUSE_STATE_COUNT]; 213 char name[32]; 214 215 // Callbacks 216 217 // Called on draw before any drawing takes place, obj = pointer to the Area 218 void (*_clear)(void *obj); 219 220 // Called on draw, obj = pointer to the Area 221 void (*_draw_foreground)(void *obj, cairo_t *c); 222 223 // Called on resize, obj = pointer to the Area 224 // Returns 1 if the new size is different than the previous size. 225 gboolean (*_resize)(void *obj); 226 227 // Called before resize, obj = pointer to the Area 228 // Returns the desired size of the Area 229 int (*_compute_desired_size)(void *obj); 230 231 // Implemented only to override the default layout algorithm for this widget. 232 // For example, if this widget is a cell in a table, its position and size should be computed here. 233 void (*_on_change_layout)(void *obj); 234 235 // Returns a copy of the tooltip to be displayed for this widget. 236 // The caller takes ownership of the pointer. 237 char *(*_get_tooltip_text)(void *obj); 238 cairo_surface_t *(*_get_tooltip_image)(void *obj); 239 240 // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. 241 // Leave this to NULL to use a default implementation. 242 gboolean (*_is_under_mouse)(void *obj, int x, int y); 243 244 // Prints the geometry of the object on stderr, with left indentation of indent spaces. 245 void (*_dump_geometry)(void *obj, int indent); 246 247 void (*_get_content_color)(void *obj, Color *color); 248 } Area; 249 250 // Initializes the Background member to default values. 251 void init_background(Background *bg); 252 253 // Layout 254 255 // Called on startup to initialize the positions of all Areas in the Area tree. 256 // Parameters: 257 // * obj: pointer to Area 258 // * offset: offset in pixels from left/top, relative to the window 259 void initialize_positions(void *obj, int offset); 260 261 // Relayouts the Area and its children. Normally called on the root of the tree (i.e. the Panel). 262 void relayout(Area *a); 263 264 // Distributes the Area's size to its children, repositioning them as needed. 265 // If maximum_size > 0, it is an upper limit for the child size. 266 int relayout_with_constraint(Area *a, int maximum_size); 267 268 int compute_desired_size(Area *a); 269 int container_compute_desired_size(Area *a); 270 271 void area_compute_text_geometry(Area *area, 272 const char *line1, 273 const char *line2, 274 PangoFontDescription *line1_font_desc, 275 PangoFontDescription *line2_font_desc, 276 int *line1_height, 277 int *line1_width, 278 int *line2_height, 279 int *line2_width); 280 int text_area_compute_desired_size(Area *area, 281 const char *line1, 282 const char *line2, 283 PangoFontDescription *line1_font_desc, 284 PangoFontDescription *line2_font_desc); 285 gboolean resize_text_area(Area *area, 286 const char *line1, 287 const char *line2, 288 PangoFontDescription *line1_font_desc, 289 PangoFontDescription *line2_font_desc, 290 int *line1_posy, 291 int *line2_posy); 292 void draw_text_area(Area *area, 293 cairo_t *c, 294 const char *line1, 295 const char *line2, 296 PangoFontDescription *line1_font_desc, 297 PangoFontDescription *line2_font_desc, 298 int line1_posy, 299 int line2_posy, 300 Color *color, 301 double scale); 302 303 int left_border_width(Area *a); 304 int right_border_width(Area *a); 305 int left_right_border_width(Area *a); 306 int top_border_width(Area *a); 307 int bottom_border_width(Area *a); 308 int top_bottom_border_width(Area *a); 309 310 int left_bg_border_width(Background *bg); 311 int right_bg_border_width(Background *bg); 312 int top_bg_border_width(Background *bg); 313 int bottom_bg_border_width(Background *bg); 314 int left_right_bg_border_width(Background *bg); 315 int top_bottom_bg_border_width(Background *bg); 316 317 // Rendering 318 319 // Sets the redraw_needed flag on the area and its descendants 320 void schedule_redraw(Area *a); 321 322 // Recreates the Area pixmap and draws the background and the foreground 323 void draw(Area *a); 324 325 // Draws the background of the Area 326 void draw_background(Area *a, cairo_t *c); 327 328 // Explores the entire Area subtree (only if the on_screen flag set) 329 // and draws the areas with the redraw_needed flag set 330 void draw_tree(Area *a); 331 332 // Clears the on_screen flag, sets the size to zero and triggers a parent resize 333 void hide(Area *a); 334 335 // Sets the on_screen flag and triggers a parent and area resize 336 void show(Area *a); 337 338 // Area tree 339 340 void add_area(Area *a, Area *parent); 341 void remove_area(Area *a); 342 void free_area(Area *a); 343 344 // Mouse events 345 346 // Returns the area under the mouse for the given x, y mouse coordinates relative to the window. 347 // If no area is found, returns the root. 348 Area *find_area_under_mouse(void *root, int x, int y); 349 350 // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. 351 gboolean area_is_under_mouse(void *obj, int x, int y); 352 353 // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. 354 // The Area will also handle clicks on the border of its ancestors, including the panel. 355 // Useful so that a click at the edge of the screen is still handled by task buttons etc., even if technically 356 // they are outside the drawing area of the button. 357 gboolean full_width_area_is_under_mouse(void *obj, int x, int y); 358 359 void instantiate_area_gradients(Area *area); 360 void free_area_gradient_instances(Area *area); 361 362 void area_dump_geometry(Area *area, int indent); 363 364 void mouse_over(Area *area, gboolean pressed); 365 void mouse_out(); 366 367 void update_gradient(GradientInstance *gi); 368 void update_dependent_gradients(Area *a); 369 370 gboolean area_is_first(void *obj); 371 gboolean area_is_last(void *obj); 372 373 #endif 374