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 has fixed size */
169     FIXEDSIZE        ,
170 /** Widget_t adjust in a aspect frame */
171     MENUITEM      ,
172 /** Widget_t request no adjustment in frame */
173     NONE          ,
174 }Gravity;
175 
176 /**
177  *
178  * @brief Resize_t             - struct used to resize child widgets
179  * @param init_x               - initial x position on Parent
180  * @param init_y               - initial y position on Parent
181  * @param init_width           - initial width
182  * @param init_height          - initial height
183  * @param scale_x              - scalling size of the x axsis
184  * @param scale_y              - scalling size of the y axsis
185  * @param cscale_x             - scalling factor of the x axsis
186  * @param cscale_y             - scalling factor of the y axsis
187  * @param ascale               - scalling factor for aspect scalling
188  */
189 
190 typedef struct {
191 /** indicate how the widget wish to be resized */
192     Gravity gravity;
193 /** initial x position on Parent */
194     int init_x;
195 /** initial y position on Parent */
196     int init_y;
197 /** initial width */
198     int init_width;
199 /** initial height */
200     int init_height;
201 /** scalling size of the x axsis */
202     float scale_x;
203 /** scalling size of the y axsis */
204     float scale_y;
205 /** scalling factor of the x axsis */
206     float cscale_x;
207 /** scalling factor of the y axsis */
208     float cscale_y;
209 /** rescalling factor of the x axsis */
210     float rcscale_x;
211 /** rescalling factor of the y axsis */
212     float rcscale_y;
213 /** scalling factor for aspect scalling */
214     float ascale;
215 } Resize_t;
216 
217 /**
218  *
219  * @brief anonymous enum       - flags to set Widget_t properties
220  * @param IS_WIDGET            - Widget_t is a sub widget
221  * @param IS_WINDOW            - Widget_t has no Widget_t parent
222  * @param IS_POPUP             - Widget_t is a pop up widget
223  * @param IS_RADIO             - Widget_t is part of a radio group
224  * @param USE_TRANSPARENCY     - Widget_t need transparent draw (buffer)
225  * @param HAS_FOCUS            - Mouse pointer is above Widget_t
226  * @param HAS_POINTER          - Mouse pointer is pressed on Widget_t
227  * @param HAS_TOOLTIP          - Widget_t have tooltip
228  * @param HAS_MEM              - Widget_t have mem to be released
229  */
230 
231 enum {
232     /** Widget_t is a sub widget */
233     IS_WIDGET         = 1<<0,
234     /** Widget_t has no Widget_t parent */
235     IS_WINDOW         = 1<<1,
236     /** Widget_t is a pop up widget */
237     IS_POPUP          = 1<<2,
238     /** Widget_t is part of a radio group */
239     IS_RADIO          = 1<<3,
240     /** Widget_t is a tooltip widget */
241     IS_TOOLTIP        = 1<<4,
242     /** Widget_t need transparent draw (buffer) */
243     USE_TRANSPARENCY  = 1<<5,
244     /** Mouse pointer is above Widget_t */
245     HAS_FOCUS         = 1<<6,
246     /** Mouse pointer is pressed on Widget_t */
247     HAS_POINTER       = 1<<7,
248     /** Widget_t have tooltip */
249     HAS_TOOLTIP       = 1<<8,
250     /** Widget_t have mem to be released */
251     HAS_MEM           = 1<<9,
252     /** Widget_t didn't receive autorepeated keys */
253     NO_AUTOREPEAT     = 1<<10,
254     /** Widget_t need fast redrawing  */
255     FAST_REDRAW       = 1<<11,
256     /** Hide Widget_t instead delete on "WM_DELETE_WINDOW"  */
257     HIDE_ON_DELETE    = 1<<12,
258     /** Widget_t reuse a surface from a other Widget_t  */
259     REUSE_IMAGE       = 1<<13,
260 };
261 
262 /**
263  *
264  * @brief Widget_t           - struct to hold the basic Widget_t info
265  * @param *app               - pointer to the main struct
266  * @param widget             - the X11 Window
267  * @param *parent            - pointer to the Parent Window or Widget_t
268  * @param event_callback     - the main XEvent callback
269  * @param func               - struct holding the event callbacks
270  * @param *surface           - pointer to the cairo xlib surface
271  * @param *cr                - pointer to the cairo xlib surface context
272  * @param *buffer            - pointer to the cairo buffer surface
273  * @param *crb               - pointer to the cairo buffer surface context
274  * @param *image             - pointer to the cairo image surface
275  * @param data               - int to hold user data
276  * @param flags              - unsigned int to hold Widget_t flags
277  * @param *label             - pointer to the widget label
278  * @param input_label        - char array the widget input label
279  * @param state              - int to hold the widget state
280  * @param pos_x              - mouse pointer x position on button press
281  * @param pos_y              - mouse pointer y position on button press
282  * @param x                  - x position of Window on Parent
283  * @param y                  - y position of Window on Parent
284  * @param width              - widget width
285  * @param height             - widget height
286  * @param scale              - struct used to resize child widgets
287  * @param *adj_x             - pointer to the x axis adjustment
288  * @param *adj_y             - pointer to the y axis adjustment
289  * @param *adj               - pointer to the adjustment in use
290  * @param *childlist         - pointer to Widget_t child list
291  * @param xic                - Locale and UTF 8 support interface
292  * @param xim                - Context to Locale and UTF 8 support
293  */
294 
295 struct Widget_t {
296 /** pointer to the main struct */
297     Xputty *app;
298 /** the X11 newly created Window */
299     Window widget;
300 /** pointer to the Parent Window or Widget_t */
301     void *parent;
302 /** pointer to the Parent struct */
303     void *parent_struct;
304 /** the main XEvent callback */
305     vfunc event_callback;
306 /** struct holding the event callbacks */
307     Func_t func;
308 /** pointer to the cairo xlib surface */
309     cairo_surface_t *surface;
310 /** pointer to the cairo xlib surface context */
311     cairo_t *cr;
312 /** pointer to the cairo buffer surface used for transparency */
313     cairo_surface_t *buffer;
314 /** pointer to the cairo buffer surface context */
315     cairo_t *crb;
316 /** pointer to the cairo image surface used to load a png */
317     cairo_surface_t *image;
318 /** int to hold user data */
319     int data;
320 /** int to hold Widget_t flags */
321     long int flags;
322 /** pointer to the widget label */
323     const char* label;
324 /** char array to hold user input */
325     char input_label[32];
326 /** pointer to the x axis adjustment */
327     Adjustment_t *adj_x;
328 /** pointer to the y axis adjustment */
329     Adjustment_t *adj_y;
330 /** pointer to the adjustment in use*/
331     Adjustment_t *adj;
332 /** pointer to Widget_t child list */
333     Childlist_t *childlist;
334 /** Locale and UTF 8 support */
335     XIC xic;
336 /** Context to Locale and UTF 8 support */
337     XIM xim;
338 /** int to hold the widget state default = 0 */
339     int state;
340 /** mouse pointer x position on button press */
341     int pos_x;
342 /** mouse pointer y position on button press */
343     int pos_y;
344 /** x position of Window related to the Parent */
345     int x;
346 /** y position of Window related to the Parent */
347     int y;
348 /** the widget size x-axis */
349     int width;
350 /** the widget size y-axis */
351     int height;
352 /** struct used to resize child widgets */
353     Resize_t scale;
354 };
355 
356 
357 /**
358  * @brief *create_window     - create a Window
359  * \n You need to create as least minimum one Window to get started.
360  * \n The first created Window is the top_level_widget()
361  * \n A Window could be created on the DefaultRootWindow() or embeded
362  * into a other XWindow
363  * @param *app               - pointer to the Xputty *main struct to use
364  * @param win                - pointer to the Parent Window (may be Root)
365  * @param x,y,width,height   - the position/geometry to create the window
366  * @return Widget_t *        - pointer to the Widget_t struct
367  */
368 
369 Widget_t *create_window(Xputty *app, Window win,
370                           int x, int y, int width, int height);
371 
372 /**
373  * @brief *create_widget      - create a widget
374  * \n A Widget_t could only be created as child of a other Widget_t
375  * \n To create a Widget_t you need to create a Widget_t with create_window()
376  * before.
377  * @param *app                - pointer to the Xputty *main struct to use
378  * @param *parent             - pointer to the Parent Widget_t
379  * @param x,y,width,height    - the position/geometry to create the widget
380  * @return Widget_t*          - pointer to the Widget_t struct
381  */
382 
383 Widget_t *create_widget(Xputty *app, Widget_t *win,
384                           int x, int y, int width, int height);
385 
386 /**
387  * @brief connect_func      - connect a event with a handler
388  * without type check. For supported events see: Func_t
389  * @param **event           - the event to connect
390  * @param *handler          - the handler to handle the event
391  * @return void
392  */
393 
394 void connect_func(void (**event)(), void (*handler)());
395 
396 /**
397  * @brief widget_set_title  - set window title for a Widget_t
398  * @param *w                - pointer to the Widget_t to set the title
399  * @param *title            - the title to store
400  * @return void
401  */
402 
403 void widget_set_title(Widget_t *w, const char *title);
404 
405 /**
406  * @brief widget_show       - map/show widget
407  * @param *w                - pointer to the Widget_t to map
408  * @return void
409  */
410 
411 void widget_show(Widget_t *w);
412 
413 /**
414  * @brief pop_widget_show_all   - map/show popup widget with all it's childs
415  * @param *w                    - pointer to the Widget_t to map
416  * @return void
417  */
418 
419 void pop_widget_show_all(Widget_t *w);
420 
421 /**
422  * @brief widget_hide       - unmap/hide a Widget_t
423  * @param *w                - pointer to the Widget_t to unmap
424  * @return void
425  */
426 
427 void widget_hide(Widget_t *w);
428 
429 /**
430  * @brief widget_show_all   - map/show Widget_t with all childs
431  * @param *w                - pointer to the Widget_t to map
432  * @return void
433  */
434 
435 void widget_show_all(Widget_t *w);
436 
437 /**
438  * @brief show_tooltip      - check if a Widget_t have a tooltip,
439  * and show it, if a tooltip is available.
440  * @param *wid              - pointer to the Widget_t receiving the event
441  * @return void
442  */
443 
444 void show_tooltip(Widget_t *wid);
445 
446 /**
447  * @brief hide_tooltip     - check if a Widget_t have a tooltip,
448  * and hide it, if a tooltip is mapped.
449  * @param *wid              - pointer to the Widget_t receiving the event
450  * @return void
451  */
452 
453 void hide_tooltip(Widget_t *wid);
454 
455 /**
456  * @brief *get_toplevel_widget - get pointer to the top level Widget_t
457  * @param *main                - pointer to the main Xputty struct
458  * @return void
459  */
460 
461 Widget_t *get_toplevel_widget(Xputty *main);
462 
463 /**
464  * @brief quit              - exit the main loop
465  * @param *w                - pointer to the Widget_t sending the request
466  * @return void
467  */
468 
469 void quit(Widget_t *w);
470 
471 /**
472  * @brief quit_widget       - remove a widget from the processing loop
473  * @param *w                - pointer to the Widget_t sending the request
474  * @return void
475  */
476 
477 void quit_widget(Widget_t *w);
478 
479 /**
480  * @brief transparent_draw  - copy parent surface to child surface
481  * \n you usaualy didn't need to call this, it's used automatically
482  * when a Widget_t have set the flag USE_TRANSPARENCY
483  * \n this is the default setting for Widget_t
484  * @param *wid              - pointer to the Widget_t receiving the event
485  * @param *user_data        - void pointer to attached user_data
486  * @return void
487  */
488 
489 void transparent_draw(void * wid, void* user_data);
490 
491 /**
492  * @brief widget_reset_scale - used to reset scaling mode after a image surface
493  * is drawn to the Widget_t surface with widget_set_scale()
494  * @param *w                 - pointer to the Widget_t sending the request
495  * @return void
496  */
497 
498 void widget_reset_scale(Widget_t *w);
499 
500 /**
501  * @brief widget_set_scale   - set scaling mode to scale a image surface
502  * to the size of the Widget_t surface
503  * @param *w                 - pointer to the Widget_t sending the request
504  * @return void
505  */
506 
507 void widget_set_scale(Widget_t *w);
508 
509 /**
510  * @brief destroy_widget    - destroy a widget
511  * \n When a Widget_t receive a destroy_widget() call, it will propagate that
512  * to all childs in it's Childlist_t. So all childs get destroyed before the
513  * Widget_t itself close.
514  * @param *w                - pointer to the Widget_t sending the request
515  * @param *main             - pointer to main struct
516  * @return void
517  */
518 
519 void destroy_widget(Widget_t *w, Xputty *main);
520 
521 /**
522  * @brief widget_event_loop - the internal widget event loop
523  * @param *w                - void pointer to the Widget_t receiving the event
524  * @param *event            - void pointer to the XEvent
525  * @param *main             - void pointer to the Xputty *main struct running
526  * the event loop
527  * @param *user_data        - void pointer to attached user_data
528  * @return void
529  */
530 
531 void widget_event_loop(void *w_, void* event, Xputty *main, void* user_data);
532 
533 /**
534  * @brief send_configure_event - send a ConfigureNotify to Widget_t
535  * \n used to resize a Widget_t
536  * @param *w                   - pointer to the Widget_t to send the notify
537  * @param x,y                  - the new Widget_t position
538  * @param width,height         - the new Widget_t size
539  * @return void
540  */
541 
542 void send_configure_event(Widget_t *w,int x, int y, int width, int height);
543 
544 /**
545  * @brief send_button_press_event   - send ButtonPress event to Widget_t
546  * \n simulate a BUTTON_PRESS Event
547  * @param *w                        - pointer to the Widget_t to send the notify
548  * @return void
549  */
550 
551 void send_button_press_event(Widget_t *w);
552 
553 /**
554  * @brief send_button_release_event - send ButtonRelease event to Widget_t
555  * \n simulate a BUTTON_RELEASE Event
556  * @param *w                        - pointer to the Widget_t to send the notify
557  * @return void
558  */
559 
560 void send_button_release_event(Widget_t *w);
561 
562 /**
563  * @brief send_systray_message      - request a systray icon for Widget_t
564  * \n currently not working
565  * @param *w                        - pointer to the Widget_t to send the notify
566  * @return void
567  */
568 
569 void send_systray_message(Widget_t *w);
570 
571 /**
572  * @brief expose_widgets    - send a expose event (EXPOSE) to a Widget_t
573  * @param w                 - the Widget_t to send the event to
574  * @return void
575  */
576 
577 void expose_widget(Widget_t *w);
578 
579 /**
580  * @brief _key_mapping      - modifier key's mapped to a integer value
581  * @param *dpy              - pointer to the Display in use
582  * @param *xkey             - the key to map
583  * @return int              - value (1-10) or 0 when not mapped
584  */
585 
586 int key_mapping(Display *dpy, XKeyEvent *xkey);
587 
588 #ifdef __cplusplus
589 }
590 #endif
591 
592 #endif //XWIDGET_H
593