1 /*************************************************************************
2 * Copyright (C) 2024 Francesco Palumbo <phranz.dev@gmail.com>, Naples (Italy)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *************************************************************************/
25 #include <X11/Xatom.h>
31 #include "evaluator.h"
37 typedef struct point_t
{
43 extern char buf
[BSIZ
];
47 extern Display
* display
;
50 extern map_strcol_t
* colors
;
51 extern unsigned long flags
;
53 extern map_widloci_t
* widlines
;
54 extern map_widloci_t
* widareas
;
55 extern map_widarcssets_t
* widarcssets
;
56 extern map_widarcssets_t
* widarcsareas
;
57 extern map_widloci_t
* widloci
;
58 extern map_widloci_t
* widpixels
;
59 extern map_widnamedpoints_t
* widnamedpoints
;
61 extern map_widwidget_t
* widgets
;
62 extern unsigned long options
;
69 #include <X11/keysym.h>
70 #include <X11/extensions/XTest.h>
72 static map_charcstr_t
* ksyms
;
74 static void fillksyms() {
78 ksyms
= alloc(map_charcstr_t
);
80 ksyms
->insert(ksyms
, ' ', "space");
81 ksyms
->insert(ksyms
, '-', "minus");
82 ksyms
->insert(ksyms
, '+', "plus");
83 ksyms
->insert(ksyms
, '.', "period");
84 ksyms
->insert(ksyms
, ',', "comma");
85 ksyms
->insert(ksyms
, ':', "colon");
86 ksyms
->insert(ksyms
, ';', "semicolon");
87 ksyms
->insert(ksyms
, '!', "exclam");
88 ksyms
->insert(ksyms
, '$', "dollar");
89 ksyms
->insert(ksyms
, '%', "percent");
90 ksyms
->insert(ksyms
, '&', "ampersand");
91 ksyms
->insert(ksyms
, '\'', "apostrophe");
92 ksyms
->insert(ksyms
, '(', "parenleft");
93 ksyms
->insert(ksyms
, ')', "parenright");
94 ksyms
->insert(ksyms
, '*', "asterisk");
95 ksyms
->insert(ksyms
, '<', "less");
96 ksyms
->insert(ksyms
, '=', "equal");
97 ksyms
->insert(ksyms
, '>', "greater");
98 ksyms
->insert(ksyms
, '?', "question");
99 ksyms
->insert(ksyms
, '@', "at");
100 ksyms
->insert(ksyms
, '[', "bracketleft");
101 ksyms
->insert(ksyms
, '\\', "backslash");
102 ksyms
->insert(ksyms
, '/', "slash");
103 ksyms
->insert(ksyms
, ']', "bracketright");
104 ksyms
->insert(ksyms
, '^', "asciicircum");
105 ksyms
->insert(ksyms
, '_', "underscore");
106 ksyms
->insert(ksyms
, '`', "grave");
107 ksyms
->insert(ksyms
, '{', "braceleft");
108 ksyms
->insert(ksyms
, '}', "braceright");
109 ksyms
->insert(ksyms
, '~', "asciitilde");
112 void sendkeys(widget_t
* w
, const char* s
) {
122 for (size_t i
=0; i
<strlen(s
); ++i
) {
125 const char* k
= ksyms
->get(ksyms
, s
[i
], &r
) ? r
: d
;
126 unsigned int kc
= XKeysymToKeycode(display
, XStringToKeysym(k
));
128 XTestFakeKeyEvent(display
, kc
, True
, 0);
129 XTestFakeKeyEvent(display
, kc
, False
, 0);
133 each(w
->to_release
, rl
,
134 XTestFakeKeyEvent(display
, rl
, False
, 0);
136 w
->to_release
->clear(w
->to_release
);
139 void sendcontrolkeys(widget_t
* w
, const char* s
) {
145 vec_str_t
* keys
= alloc(vec_str_t
);
146 ssplit(s
, ',', keys
, NULL
);
149 for (size_t i
=0; i
<keys
->count
; ++i
) {
151 keys
->get(keys
, i
, &r
);
153 keys
->remove(keys
, i
);
156 unsigned int kc
= XKeysymToKeycode(display
, XStringToKeysym(r
));
157 XTestFakeKeyEvent(display
, kc
, True
, 0);
159 w
->to_release
->push(w
->to_release
, kc
);
161 XTestFakeKeyEvent(display
, kc
, False
, 0);
173 void loadimg(widget_t
* w
, const char* p
) {
174 if (!w
|| (!w
->img
&& !p
))
179 imlib_context_set_image(w
->img
);
186 imlib_context_set_image(w
->img
);
189 imlib_context_set_display(display
);
190 imlib_context_set_visual(DefaultVisual(display
, screen
));
191 imlib_context_set_colormap(DefaultColormap(display
, screen
));
193 w
->img
= imlib_load_image(p
);
196 void updateimg(widget_t
* w
) {
200 Imlib_Image buffer
= imlib_create_image(w
->w
, w
->h
);
201 imlib_context_set_image(w
->img
);
203 int ww
= imlib_image_get_width();
204 int hh
= imlib_image_get_height();
206 imlib_context_set_blend(1);
207 imlib_context_set_image(buffer
);
208 imlib_context_set_color(w
->bg
->red
, w
->bg
->green
, w
->bg
->blue
, 255);
209 imlib_image_fill_rectangle(0, 0, w
->w
, w
->h
);
211 imlib_blend_image_onto_image(w
->img
, 0, 0, 0, ww
, hh
, 0, 0, w
->w
, w
->h
);
213 imlib_context_set_blend(0);
215 pix
= XCreatePixmap(display
, root
, w
->w
, w
->h
, DefaultDepth(display
, screen
));
217 imlib_context_set_drawable(pix
);
218 imlib_render_image_on_drawable_at_size(0, 0, w
->w
, w
->h
);
219 XSetWindowBackgroundPixmap(display
, w
->wid
, pix
);
221 imlib_context_set_image(buffer
);
223 XFreePixmap(display
, pix
);
231 intint_intint_t
pcoords() {
239 XQueryPointer(display
, root
, &w
, &w
, &C
.key
, &C
.val
, &c
.key
, &c
.val
, &m
);
246 static int getwidpid(Window w
) {
248 Atom a
= XInternAtom(display
, "_NET_WM_PID", True
);
250 XGetTextProperty(display
, w
, &d
, a
);
253 pid
= *((int*)(unsigned char*)d
.value
);
259 static void setwidpid(Window w
) {
260 Atom a
= XInternAtom(display
, "_NET_WM_PID", False
);
261 sprintf(buf
, "%d", getpid());
262 XChangeProperty(display
, w
, a
, XA_STRING
, 8, PropModeReplace
, (unsigned char*)buf
, strlen(buf
));
265 int iswin(Window p
, Window id
) {
275 XQueryTree(display
, p
, &rr
, &pr
, &cl
, &l
);
276 for (size_t i
=0; i
<l
&& !found
; ++i
)
277 found
= iswin(cl
[i
], id
);
282 static Window
parentof(Window w
) {
288 XQueryTree(display
, w
, &rr
, &pr
, &cl
, &l
);
293 static intint_t
coords(Window w
) {
294 XWindowAttributes wa
;
305 XQueryTree(display
, w
, &rr
, &pr
, &cl
, &l
);
306 XTranslateCoordinates(display
, w
, root
, 0, 0, &c
.key
, &c
.val
, &cr
);
307 XGetWindowAttributes(display
, w
, &wa
);
309 c
.key
= c
.key
? c
.key
- wa
.x
: wa
.x
;
310 c
.val
= c
.val
? c
.val
- wa
.y
: wa
.y
;
315 Window
widpid(Window w
, int p
) {
322 int pid
= getwidpid(w
);
324 debug("pid: %d, p: %d\n", pid
, p
);
327 XQueryTree(display
, w
, &rr
, &pr
, &cl
, &l
);
328 for (size_t i
=0; i
<l
; ++i
)
329 f
= widpid(cl
[i
], p
);
334 static void setclass(widget_t
* w
, const char* t
) {
335 pid_t pid
= getpid();
338 ch
.res_name
= (char*)(t
? t
: ename(w
->etype
));
340 memset(buf
, 0, sizeof(buf
));
341 sprintf(buf
, "guish-%d", pid
);
344 XSetClassHint(display
, w
->wid
, &ch
);
347 widget_t
* make(int e
, unsigned long wid
, int ww
, int hh
) {
352 w
= (widget_t
*)alloc(button_t
, ww
, hh
);
355 w
= (widget_t
*)alloc(input_t
, ww
, hh
);
358 w
= (widget_t
*)alloc(page_t
, ww
, hh
);
361 w
= (widget_t
*)alloc(label_t
, ww
, hh
);
364 w
= (widget_t
*)alloc(checkbox_t
, ww
, hh
);
367 w
= (widget_t
*)alloc(trans_t
, ww
, hh
);
375 w
->pid
= getwidpid(w
->wid
);
377 XWindowAttributes wa
;
378 XGetWindowAttributes(display
, w
->wid
, &wa
);
381 w
->b
= wa
.border_width
;
388 gc
= XCreateGC(display
, w
->wid
, 0, &v
);
395 if (options
& SHOW_ON_CREATE
)
397 if (widgets
->full(widgets
))
398 widgets
->rehash(widgets
);
400 widgets
->insert(widgets
, w
->wid
, w
);
406 void del(unsigned long long id
) {
408 if (widgets
->get(widgets
, id
, &w
)) {
409 debug("deleting window %llu\n", id
);
410 widgets
->remove(widgets
, id
);
414 ((button_t
*)w
)->free((button_t
*)w
);
417 ((input_t
*)w
)->free((input_t
*)w
);
420 ((page_t
*)w
)->free((page_t
*)w
);
423 ((label_t
*)w
)->free((label_t
*)w
);
426 ((checkbox_t
*)w
)->free((checkbox_t
*)w
);
429 ((trans_t
*)w
)->free((trans_t
*)w
);
432 if (w
->flags
& F_EXT
)
439 intint_t
textpos(widget_t
* w
, const char* s
, align a
, size_t i
, size_t t
) {
442 size_t l
= strlen(s
);
443 size_t ls
= XTextWidth(w
->fs
, s
, l
);
448 if (w
->maxwcont
< ls
)
453 c
.key
= (w
->w
- ls
) / 2;
454 c
.val
= (w
->fh
* (i
+ 1)) + w
->m
;
457 c
.key
= (w
->w
- ls
) / 2;
458 c
.val
= ((w
->h
- (w
->fh
* t
)) / 2) + (w
->fh
* (i
+ 1));
461 c
.key
= (w
->w
- ls
) / 2;
462 c
.val
= (w
->h
- ((t
- (i
+ 1)) * w
->fh
)) - w
->m
;
466 c
.val
= (w
->fh
* (i
+ 1)) + w
->m
;
470 c
.val
= ((w
->h
- (w
->fh
* t
)) / 2) + (w
->fh
* (i
+ 1));
474 c
.val
= (w
->h
- ((t
- (i
+ 1)) * w
->fh
)) - w
->m
;
477 c
.key
= w
->w
- ls
- w
->m
;
478 c
.val
= (w
->fh
* (i
+ 1)) + w
->m
;
481 c
.key
= w
->w
- ls
- w
->m
;
482 c
.val
= ((w
->h
- (w
->fh
* t
)) / 2) + (w
->fh
* (i
+ 1));
485 c
.key
= w
->w
- ls
- w
->m
;
486 c
.val
= (w
->h
- ((t
- (i
+ 1)) * w
->fh
)) - w
->m
;
492 static int getalign(const char* p
) {
497 (eq(p
, "l") || eq(p
, "left") || eq(p
, "middle-left")) ? A_ML
:
498 (eq(p
, "r") || eq(p
, "right") || eq(p
, "middle-right")) ? A_MR
:
499 (eq(p
, "c") || eq(p
, "center") || eq(p
, "middle-center")) ? A_MC
:
500 (eq(p
, "tl") || eq(p
, "top-left")) ? A_TL
:
501 (eq(p
, "tr") || eq(p
, "top-right")) ? A_TR
:
502 (eq(p
, "t") || eq(p
, "top-center")) ? A_TC
:
503 (eq(p
, "bl") || eq(p
, "bottom-left")) ? A_BL
:
504 (eq(p
, "br") || eq(p
, "bottom-right")) ? A_BR
:
505 (eq(p
, "b") || eq(p
, "bottom-center")) ? A_BC
:
509 static void movealign(widget_t
* w
, widget_t
* r
, int a
) {
515 x
= r
->x
- w
->w
- (w
->b
*2);
516 y
= (w
->h
+ (w
->b
*2)) > (r
->h
+ (r
->b
*2)) ? (r
->y
- ((w
->h
+ (w
->b
*2) - r
->h
) / 2)) : (r
->y
+ ((r
->h
- w
->h
) / 2));
519 x
= r
->x
+ r
->w
+ (r
->b
*2);
520 y
= (w
->h
+ (w
->b
*2)) > (r
->h
+ (r
->b
*2)) ? (r
->y
- ((w
->h
+ (w
->b
*2) - r
->h
) / 2)) : (r
->y
+ ((r
->h
- w
->h
) / 2));
523 x
= (w
->w
+ (w
->b
*2)) > (r
->w
+ (r
->b
*2)) ? (r
->x
- ((w
->w
+ (w
->b
*2) - r
->w
) / 2)) : (r
->x
+ ((r
->w
- w
->w
) / 2));
524 y
= (w
->h
+ (w
->b
*2)) > (r
->h
+ (r
->b
*2)) ? (r
->y
- ((w
->h
+ (w
->b
*2) - r
->h
) / 2)) : (r
->y
+ ((r
->h
- w
->h
) / 2));
527 x
= r
->x
- (w
->b
*2) - w
->w
;
528 y
= r
->y
- w
->h
- (w
->b
*2);
531 x
= r
->x
+ r
->w
+ (r
->b
*2);
532 y
= r
->y
- w
->h
- (w
->b
*2);
535 x
= (w
->w
+ (w
->b
*2)) > (r
->w
+ (r
->b
*2)) ? (r
->x
- ((w
->w
+ (w
->b
*2) - r
->w
) / 2)) : (r
->x
+ ((r
->w
- w
->w
) / 2));
536 y
= r
->y
- w
->h
- (w
->b
*2);
539 x
= r
->x
- (w
->b
*2) - w
->w
;
540 y
= r
->y
+ r
->h
+ (r
->b
*2);
543 x
= r
->x
+ r
->w
+ (r
->b
*2);
544 y
= r
->y
+ r
->h
+ (r
->b
*2);
547 x
= (w
->w
+ (w
->b
*2)) > (r
->w
+ (r
->b
*2)) ? (r
->x
- ((w
->w
+ (w
->b
*2) - r
->w
) / 2)) : (r
->x
+ ((r
->w
- w
->w
) / 2));
548 y
= r
->y
+ r
->h
+ (r
->b
*2);
553 XMoveWindow(display
, w
->wid
, x
, y
);
557 void closed(widget_t
* w
) {
559 w
->flags
|= F_CLOSED
;
560 trigger(w
->wid
, SIG_CLOSED
);
561 if (w
->etype
== E_PAGE
) {
563 each(((page_t
*)w
)->subs
, s
, closed(s
););
567 void moved(widget_t
* w
) {
568 trigger(w
->wid
, SIG_MOVED
);
570 if (w
->related
->count
) {
574 eachitem(w
->related
, widint_t
, p
,
575 if (widgets
->get(widgets
, p
->key
, &x
))
576 movealign(x
, w
, p
->val
);
578 w
->related
->remove(w
->related
, p
->key
);
583 void resized(widget_t
* w
) {
584 trigger(w
->wid
, SIG_RESIZED
);
588 if (widgets
->get(widgets
, w
->relal
->key
, &r
))
589 movealign(w
, r
, w
->relal
->val
);
593 if (w
->related
->count
) {
597 eachitem(w
->related
, widint_t
, p
,
598 if (widgets
->get(widgets
, p
->key
, &x
))
599 movealign(x
, w
, p
->val
);
601 w
->related
->remove(w
->related
, p
->key
);
606 void relaxed(widget_t
* w
, int c
) {
607 if (c
&& !(w
->flags
& F_WFIXED
) && !(w
->flags
& F_HFIXED
))
610 w
->flags
&= ~(F_WFIXED
|F_HFIXED
);
612 XSizeHints
* h
= XAllocSizeHints();
613 h
->flags
= USPosition
;
614 XSetWMSizeHints(display
, w
->wid
, h
, XA_WM_NORMAL_HINTS
);
618 void fixed(widget_t
* w
, int c
) {
619 if (c
&& w
->flags
& F_WFIXED
&& w
->flags
& F_HFIXED
)
622 w
->flags
|= (F_WFIXED
| F_HFIXED
);
624 XSizeHints
* h
= XAllocSizeHints();
625 h
->flags
= USPosition
| PMinSize
| PMaxSize
;
626 h
->min_width
= h
->max_width
= w
->w
;
627 h
->min_height
= h
->max_height
= w
->h
;
628 XSetWMSizeHints(display
, w
->wid
, h
, XA_WM_NORMAL_HINTS
);
632 void wfixed(widget_t
* w
, int c
) {
633 if (c
&& w
->flags
& F_WFIXED
&& !(w
->flags
& F_HFIXED
))
636 w
->flags
|= F_WFIXED
;
637 w
->flags
&= ~F_HFIXED
;
639 XSizeHints
* h
= XAllocSizeHints();
640 h
->flags
= USPosition
| PMinSize
| PMaxSize
;
641 h
->min_width
= h
->max_width
= w
->w
;
642 XSetWMSizeHints(display
, w
->wid
, h
, XA_WM_NORMAL_HINTS
);
646 void hfixed(widget_t
* w
, int c
) {
647 if (c
&& w
->flags
& F_HFIXED
&& !(w
->flags
& F_WFIXED
))
650 w
->flags
|= F_HFIXED
;
651 w
->flags
&= ~F_WFIXED
;
653 XSizeHints
* h
= XAllocSizeHints();
654 h
->flags
= USPosition
| PMinSize
| PMaxSize
;
655 h
->min_height
= h
->max_height
= w
->h
;
656 XSetWMSizeHints(display
, w
->wid
, h
, XA_WM_NORMAL_HINTS
);
660 void fullscreen(widget_t
* w
) {
665 e
.xclient
.type
= ClientMessage
;
666 e
.xclient
.serial
= 0;
667 e
.xclient
.send_event
= True
;
668 e
.xclient
.display
= display
;
669 e
.xclient
.window
= w
->wid
;
670 e
.xclient
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
671 e
.xclient
.format
= 32;
673 e
.xclient
.data
.l
[0] = 1;
674 e
.xclient
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_FULLSCREEN", False
);
675 e
.xclient
.data
.l
[2] = 0;
676 e
.xclient
.data
.l
[3] = 1;
677 e
.xclient
.data
.l
[4] = 0;
679 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
680 XSync(display
, False
);
682 if (w
->flags
& F_GHOST
)
687 void show(widget_t
* w
) {
691 if (w
->etype
== E_PAGE
)
694 XMapWindow(display
, w
->wid
);
695 w
->flags
|= F_VISIBLE
;
696 if (w
->flags
& F_CLOSED
)
697 w
->flags
&= ~F_CLOSED
;
698 if (w
->flags
& F_GHOST
)
701 if (w
->parent
|| w
->flags
& F_BYPASS
|| w
->flags
& F_TRAYED
)
704 XResizeWindow(display
, w
->wid
, w
->w
, w
->h
);
706 Atom wmstate
= XInternAtom(display
, "WM_STATE", False
);
713 unsigned long bafter
;
714 unsigned char *props
= NULL
;
716 while (XGetWindowProperty(display
, w
->wid
, wmstate
, 0, ~(0l), False
, AnyPropertyType
, &type
, &format
, &n
, &bafter
, &props
) == Success
) {
717 if (props
&& *props
!= WithdrawnState
)
725 void hide(widget_t
* w
) {
726 if (!w
|| !(w
->flags
& (F_VISIBLE
|F_HOVERED
)))
729 XUnmapWindow(display
, w
->wid
);
730 w
->flags
&= ~(F_VISIBLE
|F_HOVERED
);
731 if (w
->parent
|| w
->flags
& F_BYPASS
|| w
->flags
& F_TRAYED
)
734 Atom wmstate
= XInternAtom(display
, "WM_STATE", False
);
741 unsigned long bafter
;
742 unsigned char *props
;
744 while (XGetWindowProperty(display
, w
->wid
, wmstate
, 0, ~(0l), False
, AnyPropertyType
, &type
, &format
, &n
, &bafter
, &props
) == Success
) {
745 if ((props
&& *props
== WithdrawnState
) || count
> 1000)
753 if (w
->etype
== E_PAGE
)
757 void entitle(widget_t
* w
, const char* t
) {
763 w
->title
= salloc((char*)t
);
765 XStoreName(display
, w
->wid
, t
);
767 XSync(display
, False
);
770 void settop(widget_t
* w
) {
775 e
.xclient
.type
= ClientMessage
;
776 e
.xclient
.serial
= 0;
777 e
.xclient
.send_event
= True
;
778 e
.xclient
.display
= display
;
779 e
.xclient
.window
= w
->wid
;
780 e
.xclient
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
781 e
.xclient
.format
= 32;
783 e
.xclient
.data
.l
[0] = 1;
784 e
.xclient
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_ABOVE", False
);
785 e
.xclient
.data
.l
[2] = 0;
786 e
.xclient
.data
.l
[3] = 1;
787 e
.xclient
.data
.l
[4] = 0;
788 XSendEvent(display
, root
, False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
790 XSync(display
, False
);
791 if (w
->flags
& F_VISIBLE
)
795 void setdefault(widget_t
* w
) {
800 e
.xclient
.type
= ClientMessage
;
801 e
.xclient
.serial
= 0;
802 e
.xclient
.send_event
= True
;
803 e
.xclient
.display
= display
;
804 e
.xclient
.window
= w
->wid
;
805 e
.xclient
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
806 e
.xclient
.format
= 32;
808 e
.xclient
.data
.l
[0] = 0;
809 e
.xclient
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_ABOVE", False
);
810 e
.xclient
.data
.l
[2] = XInternAtom(display
, "_NET_WM_STATE_BELOW", False
);
811 e
.xclient
.data
.l
[3] = 1;
812 e
.xclient
.data
.l
[4] = 0;
814 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
816 e
.xclient
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_MODAL", False
);
817 e
.xclient
.data
.l
[2] = XInternAtom(display
, "_NET_WM_STATE_STICKY", False
);
819 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
821 e
.xclient
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_SKIP_TASKBAR", False
);
822 e
.xclient
.data
.l
[2] = XInternAtom(display
, "_NET_WM_STATE_SKIP_PAGER", False
);
824 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
826 XSync(display
, False
);
827 if (w
->flags
& F_VISIBLE
)
831 void bypasswm(widget_t
* w
, int pass
) {
832 XSetWindowAttributes wa
;
833 memset(&wa
, 0, sizeof(wa
));
834 wa
.override_redirect
= pass
;
835 XChangeWindowAttributes(display
, w
->wid
, CWOverrideRedirect
, &wa
);
837 w
->flags
|= F_BYPASS
;
839 w
->flags
&= ~F_BYPASS
;
842 void setbottom(widget_t
* w
) {
847 e
.xclient
.type
= ClientMessage
;
848 e
.xclient
.serial
= 0;
849 e
.xclient
.send_event
= True
;
850 e
.xclient
.display
= display
;
851 e
.xclient
.window
= w
->wid
;
852 e
.xclient
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
853 e
.xclient
.format
= 32;
855 e
.xclient
.data
.l
[0] = 1;
856 e
.xclient
.data
.l
[2] = XInternAtom(display
, "_NET_WM_STATE_BELOW", False
);
857 e
.xclient
.data
.l
[3] = 1;
858 e
.xclient
.data
.l
[4] = 0;
860 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, &e
);
862 XSync(display
, False
);
863 if (w
->flags
& F_VISIBLE
)
867 void wclose(widget_t
* w
) {
872 w
->flags
&= ~F_VISIBLE
;
875 intint_t
getcenter(widget_t
* w
) {
887 void center(widget_t
* w
) {
895 x
= ((w
->parent
->w
- (w
->b
*2)) / 2);
896 y
= ((w
->parent
->h
- (w
->b
*2)) / 2);
901 intint_t cpos
= getcenter(w
);
902 move(w
, x
-cpos
.key
, y
-cpos
.val
);
905 void wraise(widget_t
* w
) {
909 XRaiseWindow(display
, w
->wid
);
910 XSync(display
, False
);
913 void lower(widget_t
* w
) {
917 XLowerWindow(display
, w
->wid
);
918 XSync(display
, False
);
921 void maximize(widget_t
* w
) {
925 XClientMessageEvent e
= {0};
927 e
.type
= ClientMessage
;
929 e
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
932 e
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_MAXIMIZED_HORZ", False
);
933 e
.data
.l
[2] = XInternAtom(display
, "_NET_WM_STATE_MAXIMIZED_VERT", False
);
936 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, (XEvent
*) &e
);
937 XSync(display
, False
);
939 if (w
->flags
& F_GHOST
)
943 void resize(widget_t
* W
, int w
, int h
) {
944 if (!w
|| w
<= 0 || h
<= 0)
949 XResizeWindow(display
, W
->wid
, w
, h
);
950 XSync(display
, False
);
952 if (W
->flags
& F_WFIXED
&& W
->flags
& F_HFIXED
)
954 else if (W
->flags
& F_WFIXED
&& !(W
->flags
& F_HFIXED
))
956 else if (W
->flags
& F_HFIXED
&& !(W
->flags
& F_WFIXED
))
961 trigger(W
->wid
, SIG_RESIZED
);
965 static void setattr(widget_t
* w
, const char* k
, const char* v
) {
966 if (!strcmp(k
, "background") || !strcmp(k
, "bg")) {
969 } else if (v
[0] == '/') {
970 if (ieq(v
, "NULL") && w
->img
) {
971 imlib_context_set_image(w
->img
);
974 w
->flags
|= F_APPLYHOVER
;
977 w
->flags
&= ~F_APPLYHOVER
;
987 } else if (!strcmp(k
, "color") || !strcmp(k
, "foreground") || !strcmp(k
, "fg")) {
990 } else if (!strcmp(k
, "pressed-background") || !strcmp(k
, "pbg")) {
993 } else if (!strcmp(k
, "pressed-color") || !strcmp(k
, "pfg")) {
996 } else if (!strcmp(k
, "hovered-background") || !strcmp(k
, "hbg")) {
997 w
->mask
|= EnterWindowMask
|LeaveWindowMask
;
998 XSelectInput(display
, w
->wid
, w
->mask
);
999 w
->flags
|= F_APPLYHOVER
;
1002 } else if (!strcmp(k
, "hovered-color") || !strcmp(k
, "hfg")) {
1003 w
->mask
|= EnterWindowMask
|LeaveWindowMask
;
1004 XSelectInput(display
, w
->wid
, w
->mask
);
1007 } else if (!strcmp(k
, "border-color") || !strcmp(k
, "bc")) {
1008 XSetWindowBorder(display
, w
->wid
, addcol(v
)->pixel
);
1009 } else if (!strcmp(k
, "width") || !strcmp(k
, "w")) {
1010 w
->w
= strtoul(v
, 0, 10);
1011 resize(w
, w
->w
, w
->h
);
1012 } else if (!strcmp(k
, "height") || !strcmp(k
, "h")) {
1013 w
->h
= strtoul(v
, 0, 10);
1014 resize(w
, w
->w
, w
->h
);
1015 } else if (!strcmp(k
, "border") || !strcmp(k
, "b")) {
1016 w
->b
= strtoul(v
, 0, 10);
1017 XSetWindowBorderWidth(display
, w
->wid
, w
->b
);
1018 } else if (!strcmp(k
, "margin") || !strcmp(k
, "g")) {
1019 w
->m
= strtoul(v
, 0, 10);
1021 } else if (!strcmp(k
, "line") || !strcmp(k
, "l")) {
1022 w
->lw
= strtoul(v
, 0, 10);
1023 XSetLineAttributes(display
, gc
, w
->lw
, LineSolid
, CapRound
, JoinRound
);
1025 } else if (!strcmp(k
, "mode") || !strcmp(k
, "m")) {
1026 !strcmp(v
, "fixed") || !strcmp(v
, "f") ? fixed(w
, 1) :
1027 !strcmp(v
, "wfixed") || !strcmp(v
, "w") ? wfixed(w
, 1) :
1028 !strcmp(v
, "hfixed") || !strcmp(v
, "h") ? hfixed(w
, 1) :
1029 !strcmp(v
, "relaxed") || !strcmp(v
, "r") ? relaxed(w
, 1) :
1031 } else if (!strcmp(k
, "align") || !strcmp(k
, "a")) {
1033 (!strcmp(v
, "l") || !strcmp(v
, "left") || !strcmp(v
, "middle-left")) ? A_ML
:
1034 (!strcmp(v
, "r") || !strcmp(v
, "right") || !strcmp(v
, "middle-right")) ? A_MR
:
1035 (!strcmp(v
, "c") || !strcmp(v
, "center") || !strcmp(v
, "middle-center")) ? A_MC
:
1036 (!strcmp(v
, "tl") || !strcmp(v
, "top-left")) ? A_TL
:
1037 (!strcmp(v
, "tr") || !strcmp(v
, "top-right")) ? A_TR
:
1038 (!strcmp(v
, "t") || !strcmp(v
, "top-center")) ? A_TC
:
1039 (!strcmp(v
, "bl") || !strcmp(v
, "bottom-left")) ? A_BL
:
1040 (!strcmp(v
, "br") || !strcmp(v
, "bottom-right")) ? A_BR
:
1041 (!strcmp(v
, "b") || !strcmp(v
, "bottom-center")) ? A_BC
:
1043 if (w
->etype
== E_PAGE
) {
1044 page_t
* p
= (page_t
*)w
;
1049 setlayout(p
, p
->l
, 1);
1054 } else if (!strcmp(k
, "f") || !strcmp(k
, "font")) {
1057 XFreeFont(display
, w
->fs
);
1058 debug("trying to load font: '%s'\n", v
);
1059 w
->fs
= XLoadQueryFont(display
, v
);
1061 debug("cannot load font '%s'\n", v
);
1062 w
->fs
= XLoadQueryFont(display
, "fixed");
1066 w
->fh
= (w
->fs
->max_bounds
.ascent
+ w
->fs
->max_bounds
.descent
);
1069 fprintf(stderr
, "warning, unused attr: %s->%s\n", k
, v
);
1073 void style(widget_t
* w
, const char* s
) {
1084 for (i
=0; *p
&& (i
<BSIZ
-1); ++p
) {
1127 XColor
* addcol(const char* v
) {
1129 if (!colors
->contains(colors
, v
)) {
1130 c
= calloc(1, sizeof(XColor
));
1131 if (colors
->full(colors
))
1132 colors
->rehash(colors
);
1133 if (XParseColor(display
, DefaultColormap(display
, screen
), v
, c
) &&
1134 XAllocColor(display
, DefaultColormap(display
, screen
), c
))
1136 colors
->insert(colors
, salloc((char*)v
), c
);
1139 colors
->get(colors
, "black", &c
);
1143 colors
->get(colors
, v
, &c
);
1147 void freeze(widget_t
* w
) {
1150 if (w
->etype
== E_PAGE
)
1152 w
->flags
|= F_FREEZED
;
1155 void unfreeze(widget_t
* w
) {
1158 if (w
->etype
== E_PAGE
)
1160 w
->flags
&= ~F_FREEZED
;
1163 void fit(widget_t
* w
) {
1167 if (w
->etype
== E_PAGE
) {
1171 if (!w
->fs
|| !w
->data
|| !*w
->data
)
1174 resize(w
, w
->maxwcont
+SPIXEL
+(w
->m
*2), w
->maxhcont
+SPIXEL
+(w
->m
*2));
1177 static void nwidgets(widget_t
* w
, widgetwidget_t
* n
) {
1178 if (!w
|| !w
->parent
|| !n
)
1181 page_t
* p
= (page_t
*)w
->parent
;
1186 for (size_t i
=0; i
<p
->subs
->count
; ++i
) {
1188 p
->subs
->get(p
->subs
, i
, &g
);
1191 p
->subs
->get(p
->subs
, i
-1, &n
->key
);
1194 if (i
+1 < p
->subs
->count
)
1195 p
->subs
->get(p
->subs
, i
+1, &n
->val
);
1203 void fill_right(widget_t
* w
, int o
) {
1204 if (!w
|| !w
->parent
)
1207 page_t
* p
= (page_t
*)w
->parent
;
1212 if (!next
|| p
->l
== VL
|| o
)
1213 resize(w
, w
->parent
->w
- w
->x
- (w
->b
*2) - w
->parent
->m
, w
->h
);
1215 resize(w
, next
->x
- w
->x
- (w
->b
*2), w
->h
);
1218 void fill_bottom(widget_t
* w
, int o
) {
1219 if (!w
|| !w
->parent
)
1222 page_t
* p
= (page_t
*)w
->parent
;
1228 if (!next
|| p
->l
== HL
|| o
)
1229 resize(w
, w
->w
, w
->parent
->h
- w
->y
- (w
->b
*2) - w
->parent
->m
);
1231 resize(w
, w
->w
, next
->y
- w
->y
- (w
->b
*2));
1234 void fill(widget_t
* w
, int o
) {
1235 if (!w
|| !w
->parent
)
1241 void tray(widget_t
* w
) {
1242 if (!w
|| w
->parent
)
1245 w
->flags
|= F_TRAYED
;
1248 Atom sel
= XInternAtom (display
, "_NET_SYSTEM_TRAY_S0", False
);
1252 Window tray
= XGetSelectionOwner(display
, sel
);
1256 XSelectInput (display
,tray
,StructureNotifyMask
);
1257 memset(&ev
, 0, sizeof(ev
));
1259 ev
.xclient
.type
= ClientMessage
;
1260 ev
.xclient
.window
= tray
;
1261 ev
.xclient
.message_type
= XInternAtom(display
, "_NET_SYSTEM_TRAY_OPCODE", False
);
1262 ev
.xclient
.format
= 32;
1263 ev
.xclient
.data
.l
[0] = CurrentTime
;
1264 ev
.xclient
.data
.l
[1] = 0;
1265 ev
.xclient
.data
.l
[2] = w
->wid
;
1266 ev
.xclient
.data
.l
[3] = 0;
1267 ev
.xclient
.data
.l
[4] = 0;
1269 XSendEvent(display
, tray
, False
, NoEventMask
, &ev
);
1270 XSync(display
, False
);
1272 while (parentof(w
->wid
) == root
)
1274 if (!(w
->flags
& F_VISIBLE
))
1275 XUnmapWindow(display
, w
->wid
);
1277 intint_t tc
= coords(w
->wid
);
1283 void ghost(widget_t
* w
) {
1286 w
->flags
|= F_GHOST
;
1288 XClientMessageEvent e
= {0};
1290 e
.type
= ClientMessage
;
1292 e
.message_type
= XInternAtom(display
, "_NET_WM_STATE", False
);
1295 e
.data
.l
[1] = XInternAtom(display
, "_NET_WM_STATE_SKIP_TASKBAR", False
);
1300 XSendEvent(display
, DefaultRootWindow(display
), False
, SubstructureRedirectMask
|SubstructureNotifyMask
, (XEvent
*) &e
);
1301 XSync(display
, False
);
1304 void movealigns(widget_t
* w
, widget_t
* r
, const char* p
) {
1308 movealign(w
, r
, getalign(p
));
1311 void move(widget_t
* w
, int x
, int y
) {
1317 XMoveWindow(display
, w
->wid
, x
, y
);
1321 void focus(widget_t
* w
) {
1322 if (!w
|| !(w
->flags
& F_VISIBLE
))
1325 XSetInputFocus(display
, w
->wid
, RevertToNone
, CurrentTime
);
1328 void settext(widget_t
* w
, const char* t
) {
1333 w
->data
= salloc((char*)t
);
1337 void addtext(widget_t
* w
, const char* t
) {
1340 w
->data
= w
->data
? sadd(w
->data
, t
) : salloc((char*)t
);
1344 void pressed(widget_t
* w
, int b
) {
1346 (b
== MOUSE_LEFT
) ? F_LPRESSED
:
1347 (b
== MOUSE_RIGHT
) ? F_RPRESSED
:
1348 (b
== MOUSE_MIDDLE
) ? F_MPRESSED
:
1353 (b
== MOUSE_LEFT
) ? SIG_LPRESSED
:
1354 (b
== MOUSE_RIGHT
) ? SIG_RPRESSED
:
1355 (b
== MOUSE_MIDDLE
) ? SIG_MPRESSED
:
1358 trigger(w
->wid
, SIG_PRESSED
);
1362 if (!w
->tpress
.tv_usec
) {
1363 gettimeofday(&w
->tpress
, NULL
);
1366 gettimeofday(&now
, NULL
);
1368 msec
= ((now
.tv_sec
* 1000) + (now
.tv_usec
/ 1000)) -
1369 ((w
->tpress
.tv_sec
* 1000) + (w
->tpress
.tv_usec
/ 1000));
1371 if (msec
>= 0 && msec
<= 300) {
1373 (b
== MOUSE_LEFT
) ? F_LDCLICKED
:
1374 (b
== MOUSE_RIGHT
) ? F_RDCLICKED
:
1375 (b
== MOUSE_MIDDLE
) ? F_MDCLICKED
:
1378 gettimeofday(&w
->tpress
, NULL
);
1381 void released(widget_t
* w
, int b
) {
1383 (b
== MOUSE_LEFT
) ? ~F_LPRESSED
:
1384 (b
== MOUSE_RIGHT
) ? ~F_RPRESSED
:
1385 (b
== MOUSE_MIDDLE
) ? ~F_MPRESSED
:
1390 (b
== MOUSE_LEFT
) ? SIG_LRELEASED
:
1391 (b
== MOUSE_RIGHT
) ? SIG_RRELEASED
:
1392 (b
== MOUSE_MIDDLE
) ? SIG_MRELEASED
:
1395 trigger(w
->wid
, SIG_RELEASED
);
1397 (b
== MOUSE_LEFT
? F_LDCLICKED
:
1398 b
== MOUSE_RIGHT
? F_RDCLICKED
:
1399 b
== MOUSE_MIDDLE
? F_MDCLICKED
:
1403 (b
== MOUSE_LEFT
) ? SIG_LDCLICKED
:
1404 (b
== MOUSE_RIGHT
) ? SIG_RDCLICKED
:
1405 (b
== MOUSE_MIDDLE
) ? SIG_MDCLICKED
:
1407 trigger(w
->wid
, SIG_DCLICKED
);
1409 (b
== MOUSE_LEFT
) ? ~F_LDCLICKED
:
1410 (b
== MOUSE_RIGHT
) ? ~F_RDCLICKED
:
1411 (b
== MOUSE_MIDDLE
) ? ~F_MDCLICKED
:
1415 (b
== MOUSE_LEFT
) ? SIG_LCLICKED
:
1416 (b
== MOUSE_RIGHT
) ? SIG_RCLICKED
:
1417 (b
== MOUSE_MIDDLE
) ? SIG_MCLICKED
:
1419 trigger(w
->wid
, SIG_CLICKED
);
1423 void scroll(widget_t
* w
, int d
) {
1425 trigger(w
->wid
, SIG_SCROLLUP
);
1427 trigger(w
->wid
, SIG_SCROLLDOWN
);
1430 void write_align(widget_t
* w
, const char* s
, align a
, intint_t
* r
) {
1431 if (!s
|| !gc
|| !w
->fs
)
1437 each(w
->ll
, ls
, zfree(ls
););
1438 w
->ll
->clear(w
->ll
);
1440 ssplit(s
, '\n', w
->ll
, "");
1442 for (size_t i
=0; i
<w
->ll
->count
; ++i
) {
1443 if (w
->ll
->get(w
->ll
, i
, &ls
)) {
1446 if (w
->ll
->get(w
->ll
, i
+1, &n
) && !*n
) {
1448 w
->ll
->remove(w
->ll
, i
+1);
1453 w
->maxhcont
= w
->ll
->count
* w
->fh
;
1454 for (size_t i
=0; i
<w
->ll
->count
; ++i
) {
1455 w
->ll
->get(w
->ll
, i
, &ls
);
1457 c
= textpos(w
, ls
, a
, i
, w
->ll
->count
);
1458 XDrawString(display
, w
->wid
, gc
, c
.key
, c
.val
, ls
, l
);
1466 void addpoints(widget_t
* w
, char* col
, vec_int_t
* ps
) {
1470 widloci
= alloc(map_widloci_t
);
1473 if (!widloci
->get(widloci
, w
->wid
, &s
)) {
1475 widloci
->insert(widloci
, w
->wid
, s
);
1477 points_t
* m
= alloc(points_t
);
1478 m
->count
= ps
->count
/ 2;
1479 m
->ps
= malloc(sizeof(XPoint
)*(ps
->count
/2));
1481 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1484 s
->loci
->push(s
->loci
, m
);
1490 ps
->pop_back(ps
, &x
);
1491 ps
->pop_back(ps
, &y
);
1494 s
->cols
->push(s
->cols
, salloc(col
));
1500 void addpixels(widget_t
* w
, char* col
, vec_int_t
* ps
) {
1504 widpixels
= alloc(map_widloci_t
);
1507 if (!widpixels
->get(widpixels
, w
->wid
, &s
)) {
1509 widpixels
->insert(widpixels
, w
->wid
, s
);
1511 points_t
* m
= alloc(points_t
);
1512 m
->count
= ps
->count
/ 2;
1513 m
->ps
= malloc(sizeof(XPoint
)*(ps
->count
/2));
1515 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1518 s
->loci
->push(s
->loci
, m
);
1524 ps
->pop_back(ps
, &x
);
1525 ps
->pop_back(ps
, &y
);
1528 s
->cols
->push(s
->cols
, salloc(col
));
1534 void addlines(widget_t
* w
, char* col
, vec_int_t
* ps
) {
1538 widlines
= alloc(map_widloci_t
);
1541 if (!widlines
->get(widlines
, w
->wid
, &s
)) {
1543 widlines
->insert(widlines
, w
->wid
, s
);
1546 m
= malloc(sizeof(XPoint
)*(ps
->count
/2));
1548 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1551 points_t
* p
= alloc(points_t
);
1552 p
->count
= ps
->count
/ 2;
1557 for (size_t i
=0; ps
->count
; ++i
) {
1558 ps
->pop_back(ps
, &x
);
1559 ps
->pop_back(ps
, &y
);
1563 s
->cols
->push(s
->cols
, salloc(col
));
1564 s
->loci
->push(s
->loci
, p
);
1568 void addarcs(widget_t
* w
, int area
, char* col
, vec_int_t
* xas
) {
1571 map_widarcssets_t
** as
= area
? &widarcsareas
: &widarcssets
;
1574 *as
= alloc(map_widarcssets_t
);
1576 arcssets_t
* s
= NULL
;
1577 if (!(*as
)->get(*as
, w
->wid
, &s
)) {
1578 s
= alloc(arcssets_t
);
1579 (*as
)->insert(*as
, w
->wid
, s
);
1582 m
= malloc(sizeof(XArc
)*(xas
->count
/6));
1584 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1587 arcs_t
* a
= alloc(arcs_t
);
1588 a
->count
= xas
->count
/ 6;
1591 for (size_t i
=0; xas
->count
; ++i
) {
1599 xas
->pop_back(xas
, &x
);
1600 xas
->pop_back(xas
, &y
);
1601 xas
->pop_back(xas
, &ww
);
1602 xas
->pop_back(xas
, &hh
);
1603 xas
->pop_back(xas
, &alpha
);
1604 xas
->pop_back(xas
, &beta
);
1610 m
[i
].angle1
= alpha
*64;
1611 m
[i
].angle2
= beta
*64;
1613 s
->arcssets
->push(s
->arcssets
, a
);
1614 s
->cols
->push(s
->cols
, salloc(col
));
1618 void addarea(widget_t
* w
, char* col
, vec_int_t
* ps
) {
1622 widareas
= alloc(map_widloci_t
);
1624 if (!widareas
->get(widareas
, w
->wid
, &s
)) {
1626 widareas
->insert(widareas
, w
->wid
, s
);
1629 points_t
* m
= alloc(points_t
);
1630 m
->ps
= malloc(sizeof(XPoint
)*(ps
->count
/2));
1631 m
->count
= ps
->count
/ 2;
1633 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1638 for (size_t i
=0; ps
->count
; ++i
) {
1639 ps
->pop_back(ps
, &x
);
1640 ps
->pop_back(ps
, &y
);
1644 s
->loci
->push(s
->loci
, m
);
1645 s
->cols
->push(s
->cols
, salloc(col
));
1649 void addnamedpoint(widget_t
* w
, char* col
, char* n
, int x
, int y
) {
1652 if (!widnamedpoints
)
1653 widnamedpoints
= alloc(map_widnamedpoints_t
);
1654 namedpoints_t
* s
= NULL
;
1655 if (!widnamedpoints
->get(widnamedpoints
, w
->wid
, &s
)) {
1656 s
= alloc(namedpoints_t
);
1657 widnamedpoints
->insert(widnamedpoints
, w
->wid
, s
);
1659 s
->ps
->push(s
->ps
, x
);
1660 s
->ps
->push(s
->ps
, y
);
1661 s
->names
->push(s
->names
, salloc(n
));
1662 s
->cols
->push(s
->cols
, salloc(col
));
1666 static XPoint
* points_to_normal_coords(widget_t
* w
, points_t
* ps
) {
1667 XPoint
* cps
= malloc(sizeof(XPoint
)*ps
->count
);
1668 memcpy(cps
, ps
->ps
, sizeof(XPoint
)*ps
->count
);
1670 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1673 for (size_t j
=0; j
<ps
->count
; ++j
)
1674 cps
[j
].y
= w
->h
-cps
[j
].y
;
1678 static XArc
* arcs_to_normal_coords(widget_t
* w
, arcs_t
* as
) {
1679 XArc
* cas
= malloc(sizeof(XArc
)*as
->count
);
1680 memcpy(cas
, as
->as
, sizeof(XArc
)*as
->count
);
1682 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1685 for (size_t i
=0; i
<as
->count
; ++i
) {
1686 cas
[i
].x
= cas
[i
].x
- (cas
[i
].width
/ 2);
1687 cas
[i
].y
= w
->h
- cas
[i
].y
- (cas
[i
].height
/ 2);
1692 void drawnamedpoints(widget_t
* w
) {
1694 if (widnamedpoints
->get(widnamedpoints
, w
->wid
, &s
)) {
1700 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1701 s
->cols
->get(s
->cols
, i
, &col
);
1702 s
->names
->get(s
->names
, i
, &name
);
1703 s
->ps
->get(s
->ps
, i
*2, &x
);
1704 s
->ps
->get(s
->ps
, i
*2+1, &y
);
1706 XSetForeground(display
, gc
, c
->pixel
);
1707 XDrawArc(display
, w
->wid
, gc
, x
, w
->h
-y
, w
->lw
, w
->lw
, 0, 360*64);
1708 XDrawString(display
, w
->wid
, gc
, x
, w
->h
-y
, name
, strlen(name
));
1713 void drawpixels(widget_t
* w
) {
1715 if (widpixels
->get(widpixels
, w
->wid
, &s
)) {
1719 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1720 s
->cols
->get(s
->cols
, i
, &col
);
1721 s
->loci
->get(s
->loci
, i
, &ps
);
1723 XSetForeground(display
, gc
, c
->pixel
);
1724 XPoint
* cps
= points_to_normal_coords(w
, ps
);
1725 XDrawPoints(display
, w
->wid
, gc
, cps
, ps
->count
, CoordModeOrigin
);
1731 void drawpoints(widget_t
* w
) {
1733 if (widloci
->get(widloci
, w
->wid
, &s
)) {
1737 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1738 s
->cols
->get(s
->cols
, i
, &col
);
1739 s
->loci
->get(s
->loci
, i
, &ps
);
1741 XSetForeground(display
, gc
, c
->pixel
);
1742 XArc
* cas
= malloc(sizeof(XArc
)*ps
->count
);
1744 fprintf(stderr
, "FATAL ERROR: cannot allocate memory.\n");
1747 for (size_t j
=0; j
<ps
->count
; ++j
) {
1748 cas
[j
].x
= ps
->ps
[j
].x
;
1749 cas
[j
].y
= w
->h
- ps
->ps
[j
].y
;
1750 cas
[j
].width
= w
->lw
;
1751 cas
[j
].height
= w
->lw
;
1753 cas
[j
].angle2
= 360*64;
1755 XDrawArcs(display
, w
->wid
, gc
, cas
, ps
->count
);
1761 void drawlines(widget_t
* w
) {
1763 if (widlines
->get(widlines
, w
->wid
, &s
)) {
1767 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1768 s
->cols
->get(s
->cols
, i
, &col
);
1769 s
->loci
->get(s
->loci
, i
, &ps
);
1771 XSetForeground(display
, gc
, c
->pixel
);
1772 XPoint
* cps
= points_to_normal_coords(w
, ps
);
1773 XDrawLines(display
, w
->wid
, gc
, cps
, ps
->count
, CoordModeOrigin
);
1779 static void drawarcs_fill(widget_t
* w
, int fill
) {
1781 int (*oparc
)(Display
*, Drawable
, GC
, XArc
*, int);
1782 map_widarcssets_t
** set
;
1786 set
= &widarcsareas
;
1791 if ((*set
)->get(*set
, w
->wid
, &s
)) {
1794 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1795 s
->cols
->get(s
->cols
, i
, &col
);
1797 XSetForeground(display
, gc
, c
->pixel
);
1798 for (size_t j
=0; j
<s
->arcssets
->count
; ++j
) {
1800 s
->arcssets
->get(s
->arcssets
, j
, &arcs
);
1801 XArc
* carcs
= arcs_to_normal_coords(w
, arcs
);
1802 oparc(display
, w
->wid
, gc
, carcs
, arcs
->count
);
1809 void drawarcs(widget_t
* w
) {
1810 drawarcs_fill(w
, 0);
1813 void drawareas(widget_t
* w
) {
1815 if (!widareas
->get(widareas
, w
->wid
, &s
))
1818 for (size_t i
=0; i
<s
->cols
->count
; ++i
) {
1821 s
->cols
->get(s
->cols
, i
, &col
);
1822 s
->loci
->get(s
->loci
, i
, &ps
);
1824 XColor
* c
= addcol(col
);
1825 XSetForeground(display
, gc
, c
->pixel
);
1827 XPoint
* cps
= points_to_normal_coords(w
, ps
);
1828 XFillPolygon(display
, w
->wid
, gc
, cps
, ps
->count
, Complex
, CoordModeOrigin
);
1833 void drawarcsareas(widget_t
* w
) {
1834 drawarcs_fill(w
, 1);
1837 void clear(widget_t
* w
) {
1841 w
->data
= salloc("");
1847 void tgrip(widget_t
* w
) {
1848 if (w
->flags
& F_GRIP
) {
1849 w
->flags
&= ~F_GRIP
;
1850 if (!(w
->flags
& (F_XMOV
|F_YMOV
))) {
1851 w
->mask
&= ~ButtonMotionMask
;
1852 XSelectInput(display
, w
->wid
, w
->mask
);
1856 w
->flags
&= ~(F_XMOV
|F_YMOV
);
1857 w
->mask
|= ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
;
1858 XSelectInput(display
, w
->wid
, w
->mask
);
1862 void txmov(widget_t
* w
) {
1863 if (w
->flags
& F_XMOV
) {
1864 w
->flags
&= ~F_XMOV
;
1865 if (!(w
->flags
& F_YMOV
)) {
1866 w
->mask
&= ~ButtonMotionMask
;
1867 XSelectInput(display
, w
->wid
, w
->mask
);
1870 w
->flags
&= ~F_GRIP
;
1872 w
->mask
|= ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
;
1873 XSelectInput(display
, w
->wid
, w
->mask
);
1877 void tymov(widget_t
* w
) {
1878 if (w
->flags
& F_YMOV
) {
1879 w
->flags
&= ~F_YMOV
;
1880 if (!(w
->flags
& F_XMOV
)) {
1881 w
->mask
&= ~ButtonMotionMask
;
1882 XSelectInput(display
, w
->wid
, w
->mask
);
1885 w
->flags
&= ~F_GRIP
;
1887 w
->mask
|= ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
;
1888 XSelectInput(display
, w
->wid
, w
->mask
);
1892 void penter(widget_t
* w
) {
1893 trigger(w
->wid
, SIG_ENTER
);
1896 void pleave(widget_t
* w
) {
1897 trigger(w
->wid
, SIG_LEAVE
);
1900 void focused(widget_t
* w
) {
1901 trigger(w
->wid
, SIG_FOCUS
);
1904 void unfocused(widget_t
* w
) {
1905 trigger(w
->wid
, SIG_UNFOCUS
);
1908 void event(widget_t
* w
, XEvent
* e
) {
1909 if (!w
|| w
->flags
& F_GARBAGE
)
1911 if (e
->type
== Expose
) {
1912 if (w
->flags
& F_TRAYED
) {
1913 intint_t tc
= coords(w
->wid
);
1914 if (w
->x
!= tc
.key
|| w
->y
!= tc
.val
) {
1922 } else if (e
->type
== ClientMessage
&& (Atom
)e
->xclient
.data
.l
[0] == delatom
) {
1925 } else if (!w
->parent
&& e
->type
== ConfigureNotify
) {
1926 if (w
->w
!= e
->xconfigure
.width
|| w
->h
!= e
->xconfigure
.height
) {
1927 w
->w
= e
->xconfigure
.width
;
1928 w
->h
= e
->xconfigure
.height
;
1931 } else if (w
->x
!= e
->xconfigure
.x
|| w
->y
!= e
->xconfigure
.y
) {
1932 w
->x
= e
->xconfigure
.x
;
1933 w
->y
= e
->xconfigure
.y
;
1938 if (w
->flags
& F_FREEZED
)
1940 if (e
->type
== ButtonPress
) {
1941 switch (e
->xbutton
.button
) {
1945 if (w
->flags
& (F_GRIP
|F_XMOV
|F_YMOV
)) {
1946 lrpos
.x
= e
->xmotion
.x_root
;
1947 lrpos
.y
= e
->xmotion
.y_root
;
1948 fp
.x
= e
->xmotion
.x
;
1949 fp
.y
= e
->xmotion
.y
;
1951 pressed(w
, e
->xbutton
.button
);
1953 case MOUSE_SCROLLUP
:
1956 case MOUSE_SCROLLDOWN
:
1960 } else if (e
->type
== ButtonRelease
) {
1961 switch (e
->xbutton
.button
) {
1965 released(w
, e
->xbutton
.button
);
1970 if (w
->etype
== E_CHECKBOX
)
1971 w
->flags
& F_CHECKED
? uncheck(w
) : check(w
);
1972 } else if (e
->type
== KeyPress
&& w
->etype
== E_INPUT
) {
1975 } else if (e
->type
== KeyRelease
&& w
->etype
== E_INPUT
) {
1978 } else if (e
->type
== MotionNotify
&& w
->parent
&& w
->flags
& F_GRIP
) {
1979 XMotionEvent
* m
= (XMotionEvent
*)e
;
1988 if (!w
->parent
->parent
&& !(w
->parent
->flags
& F_BYPASS
)) {
1989 w
->flags
&= ~F_GRIP
;
1998 XTranslateCoordinates(display
, root
, r
? r
->wid
: root
, m
->x_root
, m
->y_root
, &rx
, &ry
, &cr
);
1999 XTranslateCoordinates(display
, w
->wid
, p
->wid
, fp
.x
, fp
.y
, &tx
, &ty
, &cr
);
2005 (np
.x
+ p
->w
+ (p
->b
* 2)) > (r
->w
- r
->m
) ? r
->w
- r
->m
- p
->w
- (p
->b
* 2) :
2006 np
.x
> r
->m
? np
.x
:
2008 (np
.y
+ p
->h
+ (p
->b
* 2)) > (r
->h
- r
->m
) ? r
->h
- r
->m
- p
->h
- (p
->b
* 2) :
2009 np
.y
> r
->m
? np
.y
:
2012 move(p
, np
.x
, np
.y
);
2014 lrpos
.x
= m
->x_root
;
2015 lrpos
.y
= m
->y_root
;
2016 } else if (e
->type
== MotionNotify
&& w
->flags
& (F_XMOV
|F_YMOV
)) {
2017 XMotionEvent
* m
= (XMotionEvent
*)e
;
2024 if (!w
->parent
&& !(w
->flags
& F_BYPASS
)) {
2025 w
->flags
&= ~(F_XMOV
|F_YMOV
);
2031 XTranslateCoordinates(display
, root
, p
? p
->wid
: root
, m
->x_root
, m
->y_root
, &rx
, &ry
, &cr
);
2038 (np
.x
+ w
->w
+ (w
->b
* 2)) > (p
->w
- p
->m
) ? p
->w
- p
->m
- w
->w
- (w
->b
* 2) :
2039 np
.x
> p
->m
? np
.x
:
2044 (np
.y
+ w
->h
+ (w
->b
* 2)) >= (p
->h
- p
->m
) ? p
->h
- p
->m
- w
->h
- (w
->b
* 2):
2045 np
.y
> p
->m
? np
.y
:
2050 move(w
, w
->flags
& F_XMOV
? np
.x
: w
->x
, w
->flags
& F_YMOV
? np
.y
: w
->y
);
2052 lrpos
.x
= m
->x_root
;
2053 lrpos
.y
= m
->y_root
;
2054 } else if (e
->type
== EnterNotify
) {
2056 w
->flags
|= F_HOVERED
;
2060 } else if (e
->type
== LeaveNotify
&& e
->xcrossing
.detail
!= NotifyInferior
) {
2062 w
->flags
&= ~F_HOVERED
;
2064 } else if (e
->type
== FocusIn
) {
2065 if (w
->etype
== E_INPUT
) {
2066 int ret
= XGrabKeyboard(display
, w
->wid
, False
, GrabModeAsync
, GrabModeAsync
, CurrentTime
);
2068 fprintf(stderr
, "Error: unable to grab keyboard on window %lu, reason: %d\n", w
->wid
, ret
);
2071 XSync(display
, True
);
2075 w
->flags
|= F_FOCUSED
;
2077 } else if (e
->type
== FocusOut
) {
2078 if (w
->etype
== E_INPUT
)
2079 XUngrabKeyboard(display
, CurrentTime
);
2081 w
->flags
&= ~F_FOCUSED
;
2086 void relate(widget_t
* w
, widget_t
* r
, const char* p
) {
2091 r
->related
->remove(r
->related
, w
->wid
);
2095 if (r
->related
->contains(r
->related
, w
->wid
))
2098 align a
= getalign(p
);
2099 w
->relal
->key
= r
->wid
;
2101 r
->related
->insert(r
->related
, w
->wid
, a
);
2105 void widget_t_free(widget_t
* w
) {
2106 #ifdef ENABLE_IMAGES
2108 imlib_context_set_image(w
->img
);
2113 child_going(w
->parent
, w
);
2114 if (!(w
->flags
& F_EXT
))
2115 XDestroyWindow(display
, w
->wid
);
2117 XFreeFont(display
, w
->fs
);
2121 release(w
->related
);
2122 #ifdef ENABLE_CONTROL
2124 release(w
->to_release
);
2134 each(w
->ll
, s
, free(s
););
2138 if (w
->flags
& F_EXT
) {
2139 if (options
& KILL_EXTS_ON_QUIT
&& (w
->pid
!= getpid()))
2140 kill(w
->pid
, SIGTERM
);
2145 widget_t
* widget_t_init(widget_t
* w
) {
2149 memset(w
, 0, sizeof(widget_t
));
2150 w
->data
= salloc("");
2151 w
->title
= salloc("");
2155 w
->relal
= alloc(widint_t
);
2156 w
->related
= alloc(map_widint_t
);
2157 w
->ll
= alloc(vec_str_t
);
2158 #ifdef ENABLE_CONTROL
2159 w
->to_release
= alloc(vec_uint_t
);
2163 w
->fs
= XLoadQueryFont(display
, "fixed");
2165 w
->fh
= (w
->fs
->max_bounds
.ascent
+ w
->fs
->max_bounds
.descent
);
2167 w
->free
= widget_t_free
;
2172 void points_t_free(points_t
* s
) {
2177 points_t
* points_t_init(points_t
* s
) {
2181 memset(s
, 0, sizeof(points_t
));
2182 s
->free
= points_t_free
;
2187 void arcs_t_free(arcs_t
* s
) {
2192 arcs_t
* arcs_t_init(arcs_t
* s
) {
2196 memset(s
, 0, sizeof(arcs_t
));
2197 s
->free
= arcs_t_free
;
2202 void namedpoints_t_free(namedpoints_t
* s
) {
2204 each(s
->names
, c
, free(c
););
2205 each(s
->cols
, c
, free(c
););
2212 namedpoints_t
* namedpoints_t_init(namedpoints_t
* s
) {
2216 memset(s
, 0, sizeof(namedpoints_t
));
2217 s
->ps
= alloc(vec_int_t
);
2218 s
->names
= alloc(vec_str_t
);
2219 s
->cols
= alloc(vec_str_t
);
2220 s
->free
= namedpoints_t_free
;
2225 void loci_t_free(loci_t
* s
) {
2228 each(s
->cols
, c
, free(c
););
2229 each(s
->loci
, ps
, release(ps
););
2235 loci_t
* loci_t_init(loci_t
* s
) {
2239 memset(s
, 0, sizeof(loci_t
));
2240 s
->loci
= alloc(vec_points_t
);
2241 s
->cols
= alloc(vec_str_t
);
2242 s
->free
= loci_t_free
;
2247 void arcssets_t_free(arcssets_t
* s
) {
2250 each(s
->cols
, c
, free(c
););
2251 each(s
->arcssets
, as
, release(as
););
2253 release(s
->arcssets
);
2257 arcssets_t
* arcssets_t_init(arcssets_t
* s
) {
2261 memset(s
, 0, sizeof(arcssets_t
));
2262 s
->arcssets
= alloc(vec_arcs_t
);
2263 s
->cols
= alloc(vec_str_t
);
2264 s
->free
= arcssets_t_free
;