0 /*
1 * button.c - window buttons
2 */
3
4 /*
5 * Copyright 2006 Johan Veenhuizen
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28
29 #include "button.h"
30 #include "global.h"
31 #include "lib.h"
32 #include "menu.h"
33 #include "window.h"
34
35 static void setcolors(struct button *bp)
36 {
37 bp->fg = window_family_is_active(bp->window) ?
38 &color_title_active_fg : &color_title_inactive_fg;
39 bp->bg = window_family_is_active(bp->window) ?
40 &color_title_active_bg : &color_title_inactive_bg;
41 }
42
43 static unsigned long getbgpixel(struct button *bp)
44 {
45 setcolors(bp);
46 if (bp->hover && !bp->depressed)
47 return bp->bg->bright1;
48 else
49 return bp->bg->normal;
50
51 }
52
53 static void prepare_repaint(struct widget *widget)
54 {
55 struct button *bp = (struct button *)widget;
56
57 XSetWindowBackground(display, WIDGET_XWINDOW(bp), getbgpixel(bp));
58 }
59
60 static void repaint(struct widget *widget)
61 {
62 struct button *bp = (struct button *)widget;
63 unsigned long bgpixel;
64
65 setcolors(bp);
66 bgpixel = getbgpixel(bp);
67
68 /* clear */
69 XSetForeground(display, bp->gc, bgpixel);
70 XFillRectangle(display, bp->pixmap, bp->gc,
71 0, 0, WIDGET_WIDTH(bp), WIDGET_HEIGHT(bp));
72
73 /* draw */
74 XSetForeground(display, bp->gc, bp->fg->normal);
75 XSetBackground(display, bp->gc, bgpixel);
76 if (bp->image != NULL) {
77 int x, y;
78
79 x = WIDGET_WIDTH(bp) / 2 - bp->image->width / 2;
80 y = WIDGET_HEIGHT(bp) / 2 - bp->image->height / 2;
81 if (bp->depressed) {
82 x++;
83 y++;
84 }
85 putimage(display, bp->pixmap, bp->gc, bp->image, x, y);
86 }
87
88 if (bp->depressed)
89 drawdepressed(bp->pixmap, bp->gc, bp->bg,
90 0, 0, WIDGET_WIDTH(bp), WIDGET_HEIGHT(bp));
91 else
92 drawraised(bp->pixmap, bp->gc, bp->bg,
93 0, 0, WIDGET_WIDTH(bp), WIDGET_HEIGHT(bp));
94
95 /* display */
96 if (WIDGET_MAPPED(bp))
97 XCopyArea(display,
98 bp->pixmap, WIDGET_XWINDOW(bp), bp->gc,
99 0, 0, WIDGET_WIDTH(bp), WIDGET_HEIGHT(bp), 0, 0);
100 }
101
102 static void buttonevent(struct widget *widget, XEvent *ep)
103 {
104 struct button *bp = (struct button *)widget;
105 int docall;
106
107 switch (ep->type) {
108 case ButtonPress:
109 if (ep->xbutton.button != Button1) {
110 bp->acting = 0;
111 bp->depressed = 0;
112 if (ep->xbutton.button == Button3)
113 show_menu(winmenu,
114 ep->xbutton.x_root, ep->xbutton.y_root,
115 ep->xbutton.button);
116 } else {
117 bp->acting = 1;
118 bp->depressed = 1;
119 }
120 REPAINT(bp);
121 break;
122 case ButtonRelease:
123 docall = (bp->acting && bp->depressed
124 && ep->xbutton.button == Button1
125 && bp->handler != NULL);
126 bp->depressed = 0;
127 bp->acting = 0;
128 REPAINT(bp);
129 /* must call handler as the last thing, it might destroy us */
130 if (docall)
131 bp->handler(bp->window);
132 break;
133 case Expose:
134 XCopyArea(display, bp->pixmap, WIDGET_XWINDOW(bp),
135 bp->gc, ep->xexpose.x, ep->xexpose.y,
136 ep->xexpose.width, ep->xexpose.height,
137 ep->xexpose.x, ep->xexpose.y);
138 break;
139 case EnterNotify:
140 if (bp->acting)
141 bp->depressed = 1;
142 bp->hover = 1;
143 REPAINT(bp);
144 break;
145 case LeaveNotify:
146 if (bp->acting)
147 bp->depressed = 0;
148 bp->hover = 0;
149 REPAINT(bp);
150 break;
151 }
152 }
153
154 struct button *create_button(struct window *window, int x, int y,
155 int width, int height)
156 {
157 XGCValues gcval;
158 struct button *bp;
159
160 bp = MALLOC(sizeof (struct button));
161 create_widget(&bp->widget, WIDGET_BUTTON, WIDGET_XWINDOW(window),
162 InputOutput, x, y, width, height);
163
164 bp->pixmap = XCreatePixmap(display, WIDGET_XWINDOW(bp),
165 WIDGET_WIDTH(bp), WIDGET_HEIGHT(bp),
166 DefaultDepth(display, screen));
167 gcval.graphics_exposures = False;
168 bp->gc = XCreateGC(display, WIDGET_XWINDOW(bp),
169 GCGraphicsExposures, &gcval);
170 bp->image = NULL;
171
172 bp->window = window;
173 bp->acting = 0;
174 bp->depressed = 0;
175 bp->hover = 0;
176 bp->handler = NULL;
177 bp->widget.event = buttonevent;
178 XSelectInput(display, WIDGET_XWINDOW(bp),
179 ButtonPressMask | ButtonReleaseMask |
180 ExposureMask | EnterWindowMask | LeaveWindowMask);
181 bp->widget.prepare_repaint = prepare_repaint;
182 bp->widget.repaint = repaint;
183 REPAINT(bp);
184
185 map_widget(&bp->widget);
186 return bp;
187 }
188
189 void move_button(struct button *bp, int x, int y)
190 {
191 move_widget(&bp->widget, x, y);
192 }
193
194 void destroy_button(struct button *bp)
195 {
196 XFreePixmap(display, bp->pixmap);
197 XFreeGC(display, bp->gc);
198 destroy_widget(&bp->widget);
199 FREE(bp);
200 }
201
202 void set_button_handler(struct button *bp, void (*handler)(struct window *))
203 {
204 bp->handler = handler;
205 }
206
207 void set_button_image(struct button *bp, IMAGE *image)
208 {
209 if (!bp||!image) return;
210 bp->image = image;
211 REPAINT(bp);
212 }
213