1 /*
2  *                           0BSD
3  *
4  *                    BSD Zero Clause License
5  *
6  *  Copyright (c) 2019 Hermann Meyer
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted.
10 
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  *
19  */
20 
21 #pragma once
22 
23 #ifndef XWIDGET_H
24 #define XWIDGET_H
25 
26 #include "xputty.h"
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /*---------------------------------------------------------------------
33 -----------------------------------------------------------------------
34 					basic X11 widgets
35 -----------------------------------------------------------------------
36 ----------------------------------------------------------------------*/
37 
38 #define SYSTEM_TRAY_REQUEST_DOCK   0
39 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
40 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
41 
42 /**
43  * @brief *vfunc      - function pointer to connect Xevents from the main loop to Widget_t
44  * @param *widget     - void pointer to the Widget_t
45  * @param *main       - pointer to Xputty main struct running the loop
46  * @param *event      - void pointer to the XEvent
47  * @param *user_data  - void pointer to attached user_data, maybe NULL
48  * @return void
49  */
50 
51 typedef void (*vfunc)(void * widget, void * event, Xputty *main, void* user_data);
52 
53 /**
54  * @brief *evfunc     - function pointer to connect Xevents from a Widget_t to a event handler
55  * @param *widget     - void pointer to the Widget_t
56  * @param *event      - void pointer to the XEvent
57  * @param *user_data  - void pointer to attached user_data, maybe NULL
58  * @return void
59  */
60 
61 typedef void (*evfunc)(void * widget, void * event, void* user_data);
62 
63 
64 /**
65  * @brief *xevfunc     - function pointer to connect XEvents from a Widget_t to a event handler
66  * @param *widget      - void pointer to the widget
67  * @param *user_data   - void pointer to attached user_data, maybe NULL
68  * @return void
69  */
70 
71 typedef void (*xevfunc)(void * widget, void* user_data);
72 
73 /**
74  *
75  * @brief Func_t     - struct to hold all supported event callbacks
76  *
77  */
78 
79 typedef struct {
80     xevfunc expose_callback;
81     xevfunc configure_callback;
82     xevfunc enter_callback;
83     xevfunc leave_callback;
84     xevfunc adj_callback;
85     xevfunc value_changed_callback;
86     xevfunc user_callback;
87     xevfunc mem_free_callback;
88     xevfunc configure_notify_callback;
89     xevfunc map_notify_callback;
90     xevfunc unmap_notify_callback;
91     xevfunc dialog_callback;
92 
93     evfunc button_press_callback;
94     evfunc button_release_callback;
95     evfunc motion_callback;
96     evfunc key_press_callback;
97     evfunc key_release_callback;
98 } Func_t;
99 
100 /**
101  *
102  * @brief EventType         - enum to hold identifier for all supported event callbacks
103  * \n Events could be connected to a handler by using this identifier
104  * @param EXPOSE            - (*xevfunc) expose_callback(void * widget, void* user_data)
105  * @param CONFIGURE         - (*xevfunc) configure_callback(void * widget, void* user_data)
106  * @param ENTER             - (*xevfunc) enter_callback(void * widget, void* user_data)
107  * @param LEAVE             - (*xevfunc) leave_callback(void * widget, void* user_data)
108  * @param ADJ_INTERN        - (*xevfunc) adj_callback(void * widget, void* user_data)
109  * @param VALUE_CHANGED     - (*xevfunc) value_changed_callback(void * widget, void* user_data)
110  * @param USER              - (*xevfunc) user_callback(void * widget, void* user_data)
111  * @param MEM_FREE          - (*xevfunc) mem_free_callback(void * widget, void* user_data)
112  * @param CONFIGURE_NOTIFY  - (*xevfunc) configure_notify_callback(void * widget, void* user_data)
113  * @param MAP_NOTIFY        - (*xevfunc) map_notify_callback(void * widget, void* user_data)
114  * @param UNMAP_NOTIFY      - (*xevfunc) unmap_notify_callback(void * widget, void* user_data)
115  * @param DIALOG_RESPONS    - (*xevfunc) dialog_callback(void * widget, void* user_data)
116  * @param BUTTON_PRESS      - (*evfunc) button_press_callback(void * widget, void * event, void* user_data)
117  * @param BUTTON_RELEASE    - (*evfunc) button_release_callback(void * widget, void * event, void* user_data)
118  * @param POINTER_MOTION    - (*evfunc) motion_callback(void * widget, void * event, void* user_data)
119  * @param KEY_PRESS         - (*evfunc) key_press_callback(void * widget, void * event, void* user_data)
120  * @param KEY_RELEASE       - (*evfunc) key_release_callback(void * widget, void * event, void* user_data)
121  */
122 
123 typedef enum {
124     EXPOSE = 1,
125     CONFIGURE,
126     ENTER,
127     LEAVE,
128     ADJ_INTERN,
129     VALUE_CHANGED,
130     USER,
131     MEM_FREE,
132     CONFIGURE_NOTIFY,
133     MAP_NOTIFY,
134     UNMAP_NOTIFY,
135     DIALOG_RESPONSE,
136     BUTTON_PRESS,
137     BUTTON_RELEASE,
138     POINTER_MOTION,
139     KEY_PRESS,
140     KEY_RELEASE,
141 } EventType;
142 
143 /**
144  *
145  * @brief Gravity              - enum to indicate how to resize a widget
146  * @param NORTHWEST            - Widget_t adjust nord/west
147  * @param NORTHEAST            - Widget_t adjust nord/east
148  * @param SOUTHWEST            - Widget_t adjust south/west
149  * @param SOUTHEAST            - Widget_t adjust south/east
150  * @param CENTER               - Widget_t adjust centered
151  * @param ASPECT               - Widget_t adjust in a aspect frame
152  * @param NONE                 - Widget_t request no adjustment in frame
153  */
154 
155 typedef enum {
156 /** Widget_t adjust nord/west */
157     NORTHWEST    ,
158 /** Widget_t adjust nord/east */
159     NORTHEAST    ,
160 /** Widget_t adjust south/west */
161     SOUTHWEST     ,
162 /** Widget_t adjust south/east */
163     SOUTHEAST     ,
164 /** Widget_t adjust centered */
165     CENTER        ,
166 /** Widget_t adjust in a aspect frame */
167     ASPECT        ,
168 /** Widget_t adjust in a aspect frame */
169     MENUITEM      ,
170 /** Widget_t request no adjustment in frame */
171     NONE          ,
172 }Gravity;
173 
174 /**
175  *
176  * @brief Resize_t             - struct used to resize child widgets
177  * @param init_x               - initial x position on Parent
178  * @param init_y               - initial y position on Parent
179  * @param init_width           - initial width
180  * @param init_height          - initial height
181  * @param scale_x              - scalling size of the x axsis
182  * @param scale_y              - scalling size of the y axsis
183  * @param cscale_x             - scalling factor of the x axsis
184  * @param cscale_y             - scalling factor of the y axsis
185  * @param ascale               - scalling factor for aspect scalling
186  */
187 
188 typedef struct {
189 /** indicate how the widget wish to be resized */
190     Gravity gravity;
191 /** initial x position on Parent */
192     int init_x;
193 /** initial y position on Parent */
194     int init_y;
195 /** initial width */
196     int init_width;
197 /** initial height */
198     int init_height;
199 /** scalling size of the x axsis */
200     float scale_x;
201 /** scalling size of the y axsis */
202     float scale_y;
203 /** scalling factor of the x axsis */
204     float cscale_x;
205 /** scalling factor of the y axsis */
206     float cscale_y;
207 /** rescalling factor of the x axsis */
208     float rcscale_x;
209 /** rescalling factor of the y axsis */
210     float rcscale_y;
211 /** scalling factor for aspect scalling */
212     float ascale;
213 } Resize_t;
214 
215 /**
216  *
217  * @brief anonymous enum       - flags to set Widget_t propertys
218  * @param IS_WIDGET            - Widget_t is a sub widget
219  * @param IS_WINDOW            - Widget_t has no Widget_t parent
220  * @param IS_POPUP             - Widget_t is a pop up widget
221  * @param IS_RADIO             - Widget_t is part of a radio group
222  * @param USE_TRANSPARENCY     - Widget_t need transparent draw (buffer)
223  * @param HAS_FOCUS            - Mouse pointer is above Widget_t
224  * @param HAS_POINTER          - Mouse pointer is pressed on Widget_t
225  * @param HAS_TOOLTIP          - Widget_t have tooltip
226  * @param HAS_MEM              - Widget_t have mem to be released
227  */
228 
229 enum {
230     /** Widget_t is a sub widget */
231     IS_WIDGET         = 1<<0,
232     /** Widget_t has no Widget_t parent */
233     IS_WINDOW         = 1<<1,
234     /** Widget_t is a pop up widget */
235     IS_POPUP          = 1<<2,
236     /** Widget_t is part of a radio group */
237     IS_RADIO          = 1<<3,
238     /** Widget_t is a tooltip widget */
239     IS_TOOLTIP        = 1<<4,
240     /** Widget_t need transparent draw (buffer) */
241     USE_TRANSPARENCY  = 1<<5,
242     /** Mouse pointer is above Widget_t */
243     HAS_FOCUS         = 1<<6,
244     /** Mouse pointer is pressed on Widget_t */
245     HAS_POINTER       = 1<<7,
246     /** Widget_t have tooltip */
247     HAS_TOOLTIP       = 1<<8,
248     /** Widget_t have mem to be released */
249     HAS_MEM           = 1<<9,
250     /** Widget_t didn't receive autorepeated keys */
251     NO_AUTOREPEAT     = 1<<10,
252     /** Widget_t need fast redrawing  */
253     FAST_REDRAW       = 1<<11,
254     /** Hide Widget_t instead delete on "WM_DELETE_WINDOW"  */
255     HIDE_ON_DELETE    = 1<<12,
256     /** Widget_t reuse a surface from a other Widget_t  */
257     REUSE_IMAGE       = 1<<13,
258 };
259 
260 /**
261  *
262  * @brief Widget_t           - struct to hold the basic Widget_t info
263  * @param *app               - pointer to the main struct
264  * @param widget             - the X11 Window
265  * @param *parent            - pointer to the Parent Window or Widget_t
266  * @param event_callback     - the main XEvent callback
267  * @param func               - struct holding the event callbacks
268  * @param *surface           - pointer to the cairo xlib surface
269  * @param *cr                - pointer to the cairo xlib surface context
270  * @param *buffer            - pointer to the cairo buffer surface
271  * @param *crb               - pointer to the cairo buffer surface context
272  * @param *image             - pointer to the cairo image surface
273  * @param data               - int to hold user data
274  * @param flags              - unsigned int to hold Widget_t flags
275  * @param *label             - pointer to the widget label
276  * @param input_label        - char array the widget input label
277  * @param state              - int to hold the widget state
278  * @param pos_x              - mouse pointer x position on button press
279  * @param pos_y              - mouse pointer y position on button press
280  * @param x                  - x position of Window on Parent
281  * @param y                  - y position of Window on Parent
282  * @param width              - widget width
283  * @param height             - widget height
284  * @param scale              - struct used to resize child widgets
285  * @param *adj_x             - pointer to the x axis adjustment
286  * @param *adj_y             - pointer to the y axis adjustment
287  * @param *adj               - pointer to the adjustment in use
288  * @param *childlist         - pointer to Widget_t child list
289  * @param xic                - Locale and UTF 8 support interface
290  * @param xim                - Context to Locale and UTF 8 support
291  */
292 
293 struct Widget_t {
294 /** pointer to the main struct */
295     Xputty *app;
296 /** the X11 newly created Window */
297     Window widget;
298 /** pointer to the Parent Window or Widget_t */
299     void *parent;
300 /** pointer to the Parent struct */
301     void *parent_struct;
302 /** the main XEvent callback */
303     vfunc event_callback;
304 /** struct holding the event callbacks */
305     Func_t func;
306 /** pointer to the cairo xlib surface */
307     cairo_surface_t *surface;
308 /** pointer to the cairo xlib surface context */
309     cairo_t *cr;
310 /** pointer to the cairo buffer surface used for transparency */
311     cairo_surface_t *buffer;
312 /** pointer to the cairo buffer surface context */
313     cairo_t *crb;
314 /** pointer to the cairo image surface used to load a png */
315     cairo_surface_t *image;
316 /** int to hold user data */
317     int data;
318 /** int to hold Widget_t flags */
319     long int flags;
320 /** pointer to the widget label */
321     const char* label;
322 /** char array to hold user input */
323     char input_label[32];
324 /** pointer to the x axis adjustment */
325     Adjustment_t *adj_x;
326 /** pointer to the y axis adjustment */
327     Adjustment_t *adj_y;
328 /** pointer to the adjustment in use*/
329     Adjustment_t *adj;
330 /** pointer to Widget_t child list */
331     Childlist_t *childlist;
332 /** Locale and UTF 8 support */
333     XIC xic;
334 /** Context to Locale and UTF 8 support */
335     XIM xim;
336 /** int to hold the widget state default = 0 */
337     int state;
338 /** mouse pointer x position on button press */
339     int pos_x;
340 /** mouse pointer y position on button press */
341     int pos_y;
342 /** x position of Window related to the Parent */
343     int x;
344 /** y position of Window related to the Parent */
345     int y;
346 /** the widget size x-axis */
347     int width;
348 /** the widget size y-axis */
349     int height;
350 /** struct used to resize child widgets */
351     Resize_t scale;
352 };
353 
354 
355 /**
356  * @brief *create_window     - create a Window
357  * \n You need to create as least minimun one Window to get started.
358  * \n The first created Window is the top_level_widget()
359  * \n A Window could be created on the DefaultRootWindow() or embeded
360  * into a other XWindow
361  * @param *app               - pointer to the Xputty *main struct to use
362  * @param win                - pointer to the Parrent Window (may be Root)
363  * @param x,y,width,height   - the position/geometry to create the window
364  * @return Widget_t *        - pointer to the Widget_t struct
365  */
366 
367 Widget_t *create_window(Xputty *app, Window win,
368                           int x, int y, int width, int height);
369 
370 /**
371  * @brief *create_widget      - create a widget
372  * \n A Widget_t could only be created as child of a other Widget_t
373  * \n To create a Widget_t you need to create a Widget_t with create_window()
374  * before.
375  * @param *app                - pointer to the Xputty *main struct to use
376  * @param *parent             - pointer to the Parrent Widget_t
377  * @param x,y,width,height    - the position/geometry to create the widget
378  * @return Widget_t*          - pointer to the Widget_t struct
379  */
380 
381 Widget_t *create_widget(Xputty *app, Widget_t *win,
382                           int x, int y, int width, int height);
383 
384 /**
385  * @brief connect_func      - connect a event with a handler
386  * without type check. For supported events see: Func_t
387  * @param **event           - the event to connect
388  * @param *handler          - the handler to handle the event
389  * @return void
390  */
391 
392 void connect_func(void (**event)(), void (*handler)());
393 
394 /**
395  * @brief widget_set_title  - set window title for a Widget_t
396  * @param *w                - pointer to the Widget_t to set the title
397  * @param *title            - the title to store
398  * @return void
399  */
400 
401 void widget_set_title(Widget_t *w, const char *title);
402 
403 /**
404  * @brief widget_show       - map/show widget
405  * @param *w                - pointer to the Widget_t to map
406  * @return void
407  */
408 
409 void widget_show(Widget_t *w);
410 
411 /**
412  * @brief pop_widget_show_all   - map/show popup widget with all it's childs
413  * @param *w                    - pointer to the Widget_t to map
414  * @return void
415  */
416 
417 void pop_widget_show_all(Widget_t *w);
418 
419 /**
420  * @brief widget_hide       - unmap/hide a Widget_t
421  * @param *w                - pointer to the Widget_t to unmap
422  * @return void
423  */
424 
425 void widget_hide(Widget_t *w);
426 
427 /**
428  * @brief widget_show_all   - map/show Widget_t with all childs
429  * @param *w                - pointer to the Widget_t to map
430  * @return void
431  */
432 
433 void widget_show_all(Widget_t *w);
434 
435 /**
436  * @brief show_tooltip      - check if a Widget_t have a tooltip,
437  * and show it, if a tooltip is available.
438  * @param *wid              - pointer to the Widget_t receiving the event
439  * @return void
440  */
441 
442 void show_tooltip(Widget_t *wid);
443 
444 /**
445  * @brief hide_tooltip     - check if a Widget_t have a tooltip,
446  * and hide it, if a tooltip is mapped.
447  * @param *wid              - pointer to the Widget_t receiving the event
448  * @return void
449  */
450 
451 void hide_tooltip(Widget_t *wid);
452 
453 /**
454  * @brief *get_toplevel_widget - get pointer to the top level Widget_t
455  * @param *main                - pointer to the main Xputty struct
456  * @return void
457  */
458 
459 Widget_t *get_toplevel_widget(Xputty *main);
460 
461 /**
462  * @brief quit              - exit the main loop
463  * @param *w                - pointer to the Widget_t sending the request
464  * @return void
465  */
466 
467 void quit(Widget_t *w);
468 
469 /**
470  * @brief quit_widget       - remove a widget from the processing loop
471  * @param *w                - pointer to the Widget_t sending the request
472  * @return void
473  */
474 
475 void quit_widget(Widget_t *w);
476 
477 /**
478  * @brief transparent_draw  - copy parent surface to child surface
479  * \n you usaualy didn't need to call this, it's used automaticaly
480  * when a Widget_t have set the flag USE_TRANSPARENCY
481  * \n this is the default setting for Widget_t
482  * @param *wid              - pointer to the Widget_t receiving the event
483  * @param *user_data        - void pointer to attached user_data
484  * @return void
485  */
486 
487 void transparent_draw(void * wid, void* user_data);
488 
489 /**
490  * @brief widget_reset_scale - used to reset scaling mode after a image surface
491  * is drawn to the Widget_t surface with widget_set_scale()
492  * @param *w                 - pointer to the Widget_t sending the request
493  * @return void
494  */
495 
496 void widget_reset_scale(Widget_t *w);
497 
498 /**
499  * @brief widget_set_scale   - set scaling mode to scale a image surface
500  * to the size of the Widget_t surface
501  * @param *w                 - pointer to the Widget_t sending the request
502  * @return void
503  */
504 
505 void widget_set_scale(Widget_t *w);
506 
507 /**
508  * @brief destroy_widget    - destroy a widget
509  * \n When a Widget_t receive a destroy_widget() call, it will propagate that
510  * to all childs in it's Childlist_t. So all childs get destroyed before the
511  * Widget_t itself close.
512  * @param *w                - pointer to the Widget_t sending the request
513  * @param *main             - pointer to main struct
514  * @return void
515  */
516 
517 void destroy_widget(Widget_t *w, Xputty *main);
518 
519 /**
520  * @brief widget_event_loop - the internal widget event loop
521  * @param *w                - void pointer to the Widget_t receiving the event
522  * @param *event            - void pointer to the XEvent
523  * @param *main             - void pointer to the Xputty *main struct running
524  * the event loop
525  * @param *user_data        - void pointer to attached user_data
526  * @return void
527  */
528 
529 void widget_event_loop(void *w_, void* event, Xputty *main, void* user_data);
530 
531 /**
532  * @brief send_configure_event - send a ConfigureNotify to Widget_t
533  * \n used to resize a Widget_t
534  * @param *w                   - pointer to the Widget_t to send the notify
535  * @param x,y                  - the new Widget_t position
536  * @param width,height         - the new Widget_t size
537  * @return void
538  */
539 
540 void send_configure_event(Widget_t *w,int x, int y, int width, int height);
541 
542 /**
543  * @brief send_button_press_event   - send ButtonPress event to Widget_t
544  * \n simulate a BUTTON_PRESS Event
545  * @param *w                        - pointer to the Widget_t to send the notify
546  * @return void
547  */
548 
549 void send_button_press_event(Widget_t *w);
550 
551 /**
552  * @brief send_button_release_event - send ButtonRelease event to Widget_t
553  * \n simulate a BUTTON_RELEASE Event
554  * @param *w                        - pointer to the Widget_t to send the notify
555  * @return void
556  */
557 
558 void send_button_release_event(Widget_t *w);
559 
560 /**
561  * @brief send_systray_message      - request a systray icon for Widget_t
562  * \n currently not working
563  * @param *w                        - pointer to the Widget_t to send the notify
564  * @return void
565  */
566 
567 void send_systray_message(Widget_t *w);
568 
569 /**
570  * @brief expose_widgets    - send a expose event (EXPOSE) to a Widget_t
571  * @param w                 - the Widget_t to send the event to
572  * @return void
573  */
574 
575 void expose_widget(Widget_t *w);
576 
577 /**
578  * @brief _key_mapping      - modifier key's mapped to a integer value
579  * @param *dpy              - pointer to the Display in use
580  * @param *xkey             - the key to map
581  * @return int              - value (1-10) or 0 when not mapped
582  */
583 
584 int key_mapping(Display *dpy, XKeyEvent *xkey);
585 
586 #ifdef __cplusplus
587 }
588 #endif
589 
590 #endif //XWIDGET_H
591