0 /*
1 * title.c - window titles
2 */
3
4 /*
5 * Copyright 2006-2007 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 <assert.h>
27 #include <string.h>
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31
32 #include "global.h"
33 #include "menu.h"
34 #include "lib.h"
35 #include "monitor.h"
36 #include "title.h"
37 #include "window.h"
38
39 static void prepare_repaint(struct widget *widget)
40 {
41 struct title *title = (struct title *)widget;
42
43 if (window_family_is_active(title->window)) {
44 title->fg = &color_title_active_fg;
45 title->bg = &color_title_active_bg;
46 } else {
47 title->fg = &color_title_inactive_fg;
48 title->bg = &color_title_inactive_bg;
49 }
50
51 XSetWindowBackground(display, WIDGET_XWINDOW(title),
52 title->bg->normal);
53 }
54
55 static void repaint(struct widget *widget)
56 {
57 struct title *title = (struct title *)widget;
58 struct window *win = title->window;
59 struct color *fg = title->fg;
60 struct color *bg = title->bg;
61 char *buf = NULL;
62 int xpad = title_pad + 2 * font->descent; /* this looks reasonable */
63 int ypad = MAX(3, 2 * title_pad);
64 int maxwidth = window_is_active(win) ?
65 WIDGET_WIDTH(title) - 2 * xpad - ypad - WIDGET_WIDTH(title) / 5 :
66 WIDGET_WIDTH(title) - 2 * xpad;
67 int off;
68
69 /* clear */
70 XSetForeground(display, title->gc, bg->normal);
71 XFillRectangle(display, title->pixmap, title->gc,
72 0, 0, WIDGET_WIDTH(title), WIDGET_HEIGHT(title));
73
74 /* repaint */
75 if (window_is_ontop(title->window)) {
76 drawdepressed(title->pixmap, title->gc, bg,
77 0, 0, WIDGET_WIDTH(title), WIDGET_HEIGHT(title));
78 off = 1;
79 } else {
80 drawraised(title->pixmap, title->gc, bg,
81 0, 0, WIDGET_WIDTH(title), WIDGET_HEIGHT(title));
82 off = 0;
83 }
84
85 XSetForeground(display, title->gc, fg->normal);
86 if (win->name != NULL && strlen(win->name) > 0) {
87 buf = STRDUP(win->name);
88 stringfit(buf, maxwidth);
89 XDrawString(display, title->pixmap, title->gc,
90 xpad + off,
91 title_pad + font->ascent + off,
92 buf, strlen(buf));
93 }
94
95 if (window_is_active(win)) {
96 int x, y;
97 int m = 0;
98
99 x = (buf == NULL || strlen(buf) == 0) ?
100 ypad : stringwidth(buf) + 2 * xpad;
101 x += off;
102 if (x < WIDGET_WIDTH(title) - 1 - ypad) {
103 for (y = ypad + off;
104 y < WIDGET_HEIGHT(title) - 1 - ypad + off;
105 y++) {
106 XSetForeground(display, title->gc,
107 m ? bg->shadow2 : bg->bright2);
108 XDrawLine(display, title->pixmap, title->gc,
109 m + x, y,
110 m + WIDGET_WIDTH(title)-2 - ypad + off, y);
111 m = !m;
112 }
113 }
114 }
115
116 /* display */
117 if (WIDGET_MAPPED(title))
118 XCopyArea(display,
119 title->pixmap, WIDGET_XWINDOW(title), title->gc,
120 0, 0, WIDGET_WIDTH(title), WIDGET_HEIGHT(title), 0, 0);
121
122 FREE(buf);
123 }
124
125 static void titleevent(struct widget *widget, XEvent *ep)
126 {
127 struct title *title = (struct title *)widget;
128 Window dummy;
129
130 switch (ep->type) {
131 case ButtonPress:
132 if (ep->xbutton.button == Button1) {
133 if (title->lastclick > ep->xbutton.time - 250) {
134 maximize_window(title->window, ep->xbutton.x_root, ep->xbutton.y_root);
135 } else {
136 XTranslateCoordinates(display,
137 WIDGET_XWINDOW(title),
138 WIDGET_XWINDOW(title->window),
139 ep->xbutton.x,
140 ep->xbutton.y,
141 &title->xoff,
142 &title->yoff,
143 &dummy);
144 if (ep->xbutton.state & ShiftMask)
145 toggle_window_ontop(title->window);
146 set_active_window(title->window);
147
148 beginfastmove(WIDGET_XWINDOW(title));
149 title->moving = 1;
150 }
151 title->lastclick = ep->xbutton.time;
152 } else if (ep->xbutton.button == Button3)
153 show_menu(winmenu,
154 ep->xbutton.x_root, ep->xbutton.y_root,
155 ep->xbutton.button);
156 break;
157 case ButtonRelease:
158 if (ep->xbutton.button == Button1 && title->moving) {
159 title->moving = 0;
160 endfastmove();
161 for(int i=0; i<monitors_len; i++) {
162 if(ep->xbutton.x_root>monitors[i].x&&ep->xbutton.x_root<monitors[i].x+monitors[i].w&&ep->xbutton.y_root < monitors[i].y+1) {
163 maximize_window(title->window, ep->xbutton.x_root, ep->xbutton.y_root);
164 }
165 }
166
167 }
168 break;
169 case MotionNotify:
170 if (title->moving) {
171 if (ep->xmotion.state & ControlMask)
172 move_window_family(title->window,
173 ep->xmotion.x_root - title->xoff,
174 ep->xmotion.y_root - title->yoff);
175 else
176 move_window(title->window,
177 ep->xmotion.x_root - title->xoff,
178 ep->xmotion.y_root - title->yoff);
179 }
180 break;
181 case Expose:
182 XCopyArea(display, title->pixmap, WIDGET_XWINDOW(title),
183 title->gc, ep->xexpose.x, ep->xexpose.y,
184 ep->xexpose.width, ep->xexpose.height,
185 ep->xexpose.x, ep->xexpose.y);
186 break;
187 }
188 }
189
190 struct title *create_title(struct window *window, int x, int y,
191 int width, int height)
192 {
193 XGCValues gcval;
194 struct title *tp;
195
196 tp = MALLOC(sizeof (struct title));
197 create_widget(&tp->widget, WIDGET_TITLE, WIDGET_XWINDOW(window),
198 InputOutput, x, y, width, height);
199 tp->pixmap = XCreatePixmap(display, WIDGET_XWINDOW(tp),
200 tp->pixmapwidth = width, tp->pixmapheight = height,
201 DefaultDepth(display, screen));
202 gcval.graphics_exposures = False;
203 tp->gc = XCreateGC(display, WIDGET_XWINDOW(tp),
204 GCGraphicsExposures, &gcval);
205 XSetFont(display, tp->gc, font->fid);
206 tp->window = window;
207 tp->widget.event = titleevent;
208 tp->widget.prepare_repaint = prepare_repaint;
209 tp->widget.repaint = repaint;
210 XSelectInput(display, WIDGET_XWINDOW(tp),
211 ButtonPressMask | ButtonMotionMask | ButtonReleaseMask |
212 ExposureMask);
213 tp->moving = 0;
214 tp->lastclick = 0;
215 REPAINT(tp);
216 map_widget(&tp->widget);
217 return tp;
218 }
219
220 void resize_title(struct title *tp, int width, int height)
221 {
222 if (!tp) return;
223 if (width > tp->pixmapwidth || height > tp->pixmapheight) {
224 XFreePixmap(display, tp->pixmap);
225 if (width > tp->pixmapwidth)
226 tp->pixmapwidth = MAX(LARGER(tp->pixmapwidth),
227 width);
228 if (height > tp->pixmapheight)
229 tp->pixmapheight = MAX(LARGER(tp->pixmapheight),
230 height);
231 debug("increasing title pixmap size (%dx%d)",
232 tp->pixmapwidth, tp->pixmapheight);
233 tp->pixmap = XCreatePixmap(display, WIDGET_XWINDOW(tp),
234 tp->pixmapwidth, tp->pixmapheight,
235 DefaultDepth(display, screen));
236 }
237
238 resize_widget(&tp->widget, width, height);
239 REPAINT(tp);
240 }
241
242 void destroy_title(struct title *title)
243 {
244 destroy_widget(&title->widget);
245 XFreePixmap(display, title->pixmap);
246 XFreeGC(display, title->gc);
247 FREE(title);
248 }
249