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 #include "xputty.h"
22 
23 
main_init(Xputty * main)24 void main_init(Xputty *main) {
25     main->dpy = XOpenDisplay(0);
26     assert(main->dpy);
27     main->childlist = (Childlist_t*)malloc(sizeof(Childlist_t));
28     assert(main->childlist);
29     childlist_init(main->childlist);
30     main->color_scheme = (XColor_t*)malloc(sizeof(XColor_t));
31     assert(main->color_scheme);
32     set_dark_theme(main);
33     main->hold_grab = NULL;
34     main->submenu = NULL;
35     main->run = true;
36     main->small_font = 10;
37     main->normal_font = 12;
38     main->big_font = 16;
39     main->ctext = NULL;
40     main->csize = 0;
41 
42     main->dnd_source_window = 0;
43     main->dnd_version = 5;
44     main->XdndAware = XInternAtom (main->dpy, "XdndAware", False);
45     main->XdndTypeList = XInternAtom (main->dpy, "XdndTypeList", False);
46     main->XdndSelection = XInternAtom (main->dpy, "XdndSelection", False);
47     main->XdndStatus = XInternAtom (main->dpy, "XdndStatus", False);
48     main->XdndEnter = XInternAtom (main->dpy, "XdndEnter", False);
49     main->XdndPosition = XInternAtom (main->dpy, "XdndPosition", False);
50     main->XdndLeave = XInternAtom (main->dpy, "XdndLeave", False);
51     main->XdndDrop = XInternAtom (main->dpy, "XdndDrop", False);
52     main->XdndActionCopy = XInternAtom (main->dpy, "XdndActionCopy", False);
53     main->XdndFinished = XInternAtom (main->dpy, "XdndFinished", False);
54     main->dnd_type_uri = XInternAtom (main->dpy, "text/uri-list", False);
55     main->dnd_type_text = XInternAtom (main->dpy, "text/plain", False);
56     main->dnd_type_utf8 = XInternAtom (main->dpy, "UTF8_STRING", False);
57     main->dnd_type = None;
58 
59     main->selection = XInternAtom(main->dpy, "CLIPBOARD", 0);
60     main->targets_atom = XInternAtom(main->dpy, "TARGETS", 0);
61     main->text_atom = XInternAtom(main->dpy, "TEXT", 0);
62     main->UTF8 = XInternAtom(main->dpy, "UTF8_STRING", 1);
63     if (main->UTF8 == None) main->UTF8 = XA_STRING;
64 }
65 
main_run(Xputty * main)66 void main_run(Xputty *main) {
67     Widget_t * wid = main->childlist->childs[0];
68     Atom WM_DELETE_WINDOW;
69     WM_DELETE_WINDOW = XInternAtom(main->dpy, "WM_DELETE_WINDOW", True);
70     XSetWMProtocols(main->dpy, wid->widget, &WM_DELETE_WINDOW, 1);
71 
72     XEvent xev;
73     int ew;
74 
75     while (main->run && (XNextEvent(main->dpy, &xev)>=0)) {
76         if (XFilterEvent(&xev, None)) continue;
77         ew = childlist_find_widget(main->childlist, xev.xany.window);
78         if(ew  >= 0) {
79             Widget_t * w = main->childlist->childs[ew];
80             w->event_callback(w, &xev, main, NULL);
81         }
82 
83         switch (xev.type) {
84             case ButtonPress:
85             {
86                 bool is_item = False;
87                 if(main->submenu != NULL) {
88                     if (childlist_has_child(main->submenu->childlist)) {
89                         Widget_t *slider = main->submenu->childlist->childs[1];
90                         if (xev.xbutton.window == slider->widget) {
91                             break;
92                         }
93                         Widget_t *view_port = main->submenu->childlist->childs[0];
94                         int i = view_port->childlist->elem-1;
95                         for(;i>-1;i--) {
96                             Widget_t *w = view_port->childlist->childs[i];
97                             if (xev.xbutton.window == w->widget) {
98                                 is_item = True;
99                                 break;
100                             }
101                         }
102                     }
103                 }
104                 if(main->hold_grab != NULL) {
105                     if (childlist_has_child(main->hold_grab->childlist)) {
106                         Widget_t *slider = main->hold_grab->childlist->childs[1];
107                         if (xev.xbutton.window == slider->widget) {
108                             break;
109                         }
110                         Widget_t *view_port = main->hold_grab->childlist->childs[0];
111                         int i = view_port->childlist->elem-1;
112                         for(;i>-1;i--) {
113                             Widget_t *w = view_port->childlist->childs[i];
114                             if (xev.xbutton.window == w->widget) {
115                                 is_item = True;
116                                 break;
117                             }
118                         }
119                         if (xev.xbutton.window == view_port->widget) is_item = True;
120                     }
121                     if (!is_item) {
122                         XUngrabPointer(main->dpy,CurrentTime);
123                         widget_hide(main->hold_grab);
124                         main->hold_grab = NULL;
125                     }
126                 }
127             }
128             break;
129             case ClientMessage:
130             {
131                 if (xev.xclient.data.l[0] == (long int)WM_DELETE_WINDOW &&
132                         xev.xclient.window == wid->widget) {
133                     main->run = false;
134                 } else if (xev.xclient.data.l[0] == (long int)WM_DELETE_WINDOW) {
135                     int i = childlist_find_widget(main->childlist, xev.xclient.window);
136                     if(i<1) return;
137                     Widget_t *w = main->childlist->childs[i];
138                     if(w->flags & HIDE_ON_DELETE) widget_hide(w);
139                     else destroy_widget(main->childlist->childs[i],main);
140                 }
141                 break;
142             }
143         }
144     }
145 }
146 
run_embedded(Xputty * main)147 void run_embedded(Xputty *main) {
148 
149     XEvent xev;
150     int ew = -1;
151 
152     while (XPending(main->dpy) > 0) {
153         XNextEvent(main->dpy, &xev);
154         if (xev.type == ClientMessage || xev.type == SelectionNotify) {
155             Widget_t * w = main->childlist->childs[0];
156             w->event_callback(w, &xev, main, NULL);
157         }
158         ew = childlist_find_widget(main->childlist, xev.xany.window);
159         if(ew  >= 0) {
160             Widget_t * w = main->childlist->childs[ew];
161             w->event_callback(w, &xev, main, NULL);
162         }
163         switch (xev.type) {
164         case ButtonPress:
165         {
166             bool is_item = False;
167             if(main->hold_grab != NULL) {
168                 if (childlist_has_child(main->hold_grab->childlist)) {
169                     Widget_t *slider = main->hold_grab->childlist->childs[1];
170                     if (xev.xbutton.window == slider->widget) {
171                         break;
172                     }
173                     Widget_t *view_port = main->hold_grab->childlist->childs[0];
174                     int i = view_port->childlist->elem-1;
175                     for(;i>-1;i--) {
176                         Widget_t *w = view_port->childlist->childs[i];
177                         if (xev.xbutton.window == w->widget) {
178                             is_item = True;
179                             break;
180                         }
181                     }
182                     if (xev.xbutton.window == view_port->widget) is_item = True;
183                 }
184                 if (!is_item) {
185                     XUngrabPointer(main->dpy,CurrentTime);
186                     widget_hide(main->hold_grab);
187                     main->hold_grab = NULL;
188                 }
189             }
190         }
191         break;
192         case ClientMessage:
193             if (xev.xclient.data.l[0] == (long int)XInternAtom(main->dpy, "WM_DELETE_WINDOW", True) ) {
194                 int i = childlist_find_widget(main->childlist, xev.xclient.window);
195                 if(i<1) return;
196                 Widget_t *w = main->childlist->childs[i];
197                 if(w->flags & HIDE_ON_DELETE) widget_hide(w);
198                 else destroy_widget(w, main);
199             }
200         break;
201         }
202     }
203 }
204 
main_quit(Xputty * main)205 void main_quit(Xputty *main) {
206     int i = main->childlist->elem-1;
207     for(;i>-1;i--) {
208         Widget_t *w = main->childlist->childs[i];
209         destroy_widget(w, main);
210     }
211     childlist_destroy(main->childlist);
212     free(main->childlist);
213     free(main->color_scheme);
214     XCloseDisplay(main->dpy);
215     free(main->ctext);
216     debug_print("quit\n");
217 }
218