1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "wconfig.h"
22 
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #ifdef KEEP_XKB_LOCK_STATUS
26 #include <X11/XKBlib.h>
27 #endif				/* KEEP_XKB_LOCK_STATUS */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <wraster.h>
33 
34 #include "WindowMaker.h"
35 #include "GNUstep.h"
36 #include "texture.h"
37 #include "resources.h"
38 #include "screen.h"
39 #include "wcore.h"
40 #include "window.h"
41 #include "framewin.h"
42 #include "stacking.h"
43 #include "misc.h"
44 #include "event.h"
45 
46 
47 static void handleExpose(WObjDescriptor * desc, XEvent * event);
48 static void handleButtonExpose(WObjDescriptor * desc, XEvent * event);
49 
50 static void buttonMouseDown(WObjDescriptor * desc, XEvent * event);
51 static void titlebarMouseDown(WObjDescriptor * desc, XEvent * event);
52 static void resizebarMouseDown(WObjDescriptor * desc, XEvent * event);
53 
54 static void checkTitleSize(WFrameWindow * fwin);
55 
56 static void paintButton(WCoreWindow * button, WTexture * texture,
57 			unsigned long color, WPixmap * image, int pushed);
58 
59 static void updateTitlebar(WFrameWindow * fwin);
60 
61 static void allocFrameBorderPixel(Colormap colormap, const char *color_name, unsigned long **pixel);
62 
allocFrameBorderPixel(Colormap colormap,const char * color_name,unsigned long ** pixel)63 static void allocFrameBorderPixel(Colormap colormap, const char *color_name, unsigned long **pixel) {
64 	XColor xcol;
65 
66 	*pixel = NULL;
67 
68 	if (! wGetColorForColormap(colormap, color_name, &xcol))
69 		return;
70 
71 	*pixel = wmalloc(sizeof(unsigned long));
72 	if (*pixel)
73 		**pixel = xcol.pixel;
74 }
75 
wFrameWindowCreate(WScreen * scr,int wlevel,int x,int y,int width,int height,int * clearance,int * title_min,int * title_max,int flags,WTexture ** title_texture,WTexture ** resize_texture,WMColor ** color,WMFont ** font,int depth,Visual * visual,Colormap colormap)76 WFrameWindow *wFrameWindowCreate(WScreen * scr, int wlevel, int x, int y,
77 				 int width, int height, int *clearance,
78 				 int *title_min, int *title_max, int flags,
79 				 WTexture ** title_texture, WTexture ** resize_texture,
80 				 WMColor ** color, WMFont ** font,
81 				 int depth, Visual *visual, Colormap colormap)
82 {
83 	WFrameWindow *fwin;
84 
85 	fwin = wmalloc(sizeof(WFrameWindow));
86 
87 	fwin->screen_ptr = scr;
88 
89 	fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
90 
91 	fwin->title_texture = title_texture;
92 	fwin->resizebar_texture = resize_texture;
93 	fwin->title_color = color;
94 	fwin->title_clearance = clearance;
95 	fwin->title_min_height = title_min;
96 	fwin->title_max_height = title_max;
97 	fwin->font = font;
98 #ifdef KEEP_XKB_LOCK_STATUS
99 	fwin->languagemode = XkbGroup1Index;
100 	fwin->last_languagemode = XkbGroup2Index;
101 #endif
102 
103 	fwin->depth = depth;
104 	fwin->visual = visual;
105 	fwin->colormap = colormap;
106 
107 	fwin->core = wCoreCreateTopLevel(scr, x, y, width, height, (flags & WFF_BORDER)
108 					 ? scr->frame_border_width : 0, fwin->depth, fwin->visual, fwin->colormap, scr->frame_border_pixel);
109 
110 	/* setup stacking information */
111 	fwin->core->stacking = wmalloc(sizeof(WStacking));
112 	fwin->core->stacking->above = NULL;
113 	fwin->core->stacking->under = NULL;
114 	fwin->core->stacking->child_of = NULL;
115 	fwin->core->stacking->window_level = wlevel;
116 
117 	AddToStackList(fwin->core);
118 
119 	wFrameWindowUpdateBorders(fwin, flags);
120 
121 	return fwin;
122 }
123 
wFrameWindowUpdateBorders(WFrameWindow * fwin,int flags)124 void wFrameWindowUpdateBorders(WFrameWindow * fwin, int flags)
125 {
126 	int theight;
127 	int bsize;
128 	int width, height;
129 	int i;
130 	WScreen *scr = fwin->screen_ptr;
131 
132 	width = fwin->core->width;
133 	if (flags & WFF_IS_SHADED)
134 		height = -1;
135 	else
136 		height = fwin->core->height - fwin->top_width - fwin->bottom_width;
137 
138 	if (flags & WFF_TITLEBAR) {
139 		theight = WMFontHeight(*fwin->font) + (*fwin->title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
140 
141 		if (theight > *fwin->title_max_height)
142 			theight = *fwin->title_max_height;
143 
144 		if (theight < *fwin->title_min_height)
145 			theight = *fwin->title_min_height;
146 	} else {
147 		theight = 0;
148 	}
149 
150 	if (wPreferences.new_style == TS_NEW) {
151 		bsize = theight;
152 	} else if (wPreferences.new_style == TS_OLD) {
153 		bsize = theight - 7;
154 	} else {
155 		bsize = theight - 8;
156 	}
157 
158 	if (fwin->titlebar) {
159 		/* if we had a titlebar and is requesting for one,
160 		 * check if the size has changed and resize it */
161 		if (flags & WFF_TITLEBAR) {
162 			fwin->top_width = theight;
163 
164 			fwin->flags.need_texture_remake = 1;
165 
166 			if (wPreferences.new_style == TS_NEW) {
167 				if (fwin->left_button)
168 					wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
169 #ifdef XKB_BUTTON_HINT
170 				if (fwin->language_button) {
171 					if (fwin->flags.hide_left_button || !fwin->left_button
172 					    || fwin->flags.lbutton_dont_fit)
173 						wCoreConfigure(fwin->language_button, 0, 0, bsize, bsize);
174 					else
175 						wCoreConfigure(fwin->language_button, bsize, 0, bsize, bsize);
176 				}
177 #endif
178 
179 				if (fwin->right_button)
180 					wCoreConfigure(fwin->right_button, width - bsize + 1, 0, bsize, bsize);
181 
182 			} else {	/* !new_style */
183 				if (fwin->left_button)
184 					wCoreConfigure(fwin->left_button, 3, (theight - bsize) / 2, bsize, bsize);
185 #ifdef XKB_BUTTON_HINT
186 				if (fwin->language_button)
187 					wCoreConfigure(fwin->language_button, 6 + bsize, (theight - bsize) / 2,
188 						       bsize, bsize);
189 #endif
190 
191 				if (fwin->right_button)
192 					wCoreConfigure(fwin->right_button, width - bsize - 3,
193 						       (theight - bsize) / 2, bsize, bsize);
194 			}
195 			updateTitlebar(fwin);
196 		} else {
197 			/* we had a titlebar, but now we don't need it anymore */
198 			for (i = 0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
199 				FREE_PIXMAP(fwin->title_back[i]);
200 				if (wPreferences.new_style == TS_NEW) {
201 					FREE_PIXMAP(fwin->lbutton_back[i]);
202 					FREE_PIXMAP(fwin->rbutton_back[i]);
203 #ifdef XKB_BUTTON_HINT
204 					FREE_PIXMAP(fwin->languagebutton_back[i]);
205 #endif
206 				}
207 			}
208 			if (fwin->left_button)
209 				wCoreDestroy(fwin->left_button);
210 			fwin->left_button = NULL;
211 
212 #ifdef XKB_BUTTON_HINT
213 			if (fwin->language_button)
214 				wCoreDestroy(fwin->language_button);
215 			fwin->language_button = NULL;
216 #endif
217 
218 			if (fwin->right_button)
219 				wCoreDestroy(fwin->right_button);
220 			fwin->right_button = NULL;
221 
222 			wCoreDestroy(fwin->titlebar);
223 			fwin->titlebar = NULL;
224 
225 			fwin->top_width = 0;
226 		}
227 	} else {
228 		/* if we didn't have a titlebar and are being requested for
229 		 * one, create it */
230 		if (flags & WFF_TITLEBAR) {
231 			fwin->top_width = theight;
232 
233 			fwin->flags.titlebar = 1;
234 			fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width + 1, theight);
235 
236 			if (flags & WFF_LEFT_BUTTON) {
237 				fwin->flags.left_button = 1;
238 				if (wPreferences.new_style == TS_NEW) {
239 					fwin->left_button = wCoreCreate(fwin->core, 0, 0, bsize, bsize);
240 
241 					if (width < theight * 4)
242 						fwin->flags.lbutton_dont_fit = 1;
243 					else
244 						XMapRaised(dpy, fwin->left_button->window);
245 
246 				} else if (wPreferences.new_style == TS_OLD) {
247 					fwin->left_button =
248 					    wCoreCreate(fwin->titlebar, 3, (theight - bsize) / 2, bsize, bsize);
249 
250 					XSetWindowBackground(dpy, fwin->left_button->window,
251 							     scr->widget_texture->normal.pixel);
252 
253 					if (width < theight * 3)
254 						fwin->flags.lbutton_dont_fit = 1;
255 					else
256 						XMapRaised(dpy, fwin->left_button->window);
257 
258 				} else {
259 					fwin->left_button =
260 					    wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
261 								    bsize, bsize);
262 
263 					XSetWindowBackground(dpy, fwin->left_button->window,
264 							     scr->widget_texture->dark.pixel);
265 
266 					if (width < theight * 3)
267 						fwin->flags.lbutton_dont_fit = 1;
268 					else
269 						XMapRaised(dpy, fwin->left_button->window);
270 
271 				}
272 			}
273 #ifdef XKB_BUTTON_HINT
274 			if (flags & WFF_LANGUAGE_BUTTON) {
275 				fwin->flags.language_button = 1;
276 				if (wPreferences.new_style == TS_NEW) {
277 					fwin->language_button = wCoreCreate(fwin->core, bsize, 0, bsize, bsize);
278 
279 					if (width < theight * 4)
280 						fwin->flags.languagebutton_dont_fit = 1;
281 					else
282 						XMapRaised(dpy, fwin->language_button->window);
283 				} else {
284 					fwin->language_button =
285 					    wCoreCreate(fwin->titlebar, bsize + 6, (theight - bsize) / 2,
286 							bsize, bsize);
287 
288 					XSetWindowBackground(dpy, fwin->language_button->window,
289 							     scr->widget_texture->normal.pixel);
290 
291 					if (width < theight * 3)
292 						fwin->flags.languagebutton_dont_fit = 1;
293 					else
294 						XMapRaised(dpy, fwin->language_button->window);
295 				}
296 			}
297 #endif
298 
299 			if (flags & WFF_RIGHT_BUTTON) {
300 				fwin->flags.right_button = 1;
301 				if (wPreferences.new_style == TS_NEW) {
302 					fwin->right_button =
303 					    wCoreCreate(fwin->core, width - bsize + 1, 0, bsize, bsize);
304 				} else if (wPreferences.new_style == TS_OLD) {
305 					fwin->right_button =
306 					    wCoreCreate(fwin->titlebar, width - bsize - 3,
307 							(theight - bsize) / 2, bsize, bsize);
308 					XSetWindowBackground(dpy, fwin->right_button->window,
309 							     scr->widget_texture->normal.pixel);
310 				} else {
311 					fwin->right_button =
312 					    wCoreCreate(fwin->titlebar, width-bsize-3,
313 							(theight-bsize)/2, bsize, bsize);
314 					XSetWindowBackground(dpy, fwin->right_button->window,
315 							     scr->widget_texture->dark.pixel);
316 				}
317 
318 				if (width < theight * 2)
319 					fwin->flags.rbutton_dont_fit = 1;
320 				else
321 					XMapRaised(dpy, fwin->right_button->window);
322 			}
323 
324 			if (wPreferences.new_style == TS_NEW)
325 				updateTitlebar(fwin);
326 
327 			XMapRaised(dpy, fwin->titlebar->window);
328 
329 			fwin->flags.need_texture_remake = 1;
330 		}
331 	}
332 	checkTitleSize(fwin);
333 
334 	if (flags & WFF_RESIZEBAR) {
335 		fwin->bottom_width = RESIZEBAR_HEIGHT;
336 
337 		if (!fwin->resizebar) {
338 			fwin->flags.resizebar = 1;
339 			fwin->resizebar = wCoreCreate(fwin->core, 0,
340 						      height + fwin->top_width, width, RESIZEBAR_HEIGHT);
341 			fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
342 			if (width < RESIZEBAR_CORNER_WIDTH * 2 + RESIZEBAR_MIN_WIDTH) {
343 				fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH) / 2;
344 				if (fwin->resizebar_corner_width < 0)
345 					fwin->resizebar_corner_width = 0;
346 			}
347 
348 			XMapWindow(dpy, fwin->resizebar->window);
349 			XLowerWindow(dpy, fwin->resizebar->window);
350 
351 			fwin->flags.need_texture_remake = 1;
352 		} else {
353 			if (height + fwin->top_width + fwin->bottom_width != fwin->core->height)
354 				wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
355 					       width, RESIZEBAR_HEIGHT);
356 		}
357 	} else {
358 		fwin->bottom_width = 0;
359 
360 		if (fwin->resizebar) {
361 			fwin->bottom_width = 0;
362 			wCoreDestroy(fwin->resizebar);
363 			fwin->resizebar = NULL;
364 		}
365 	}
366 
367 	if (height + fwin->top_width + fwin->bottom_width != fwin->core->height && !(flags & WFF_IS_SHADED))
368 		wFrameWindowResize(fwin, width, height + fwin->top_width + fwin->bottom_width);
369 
370 	if (flags & WFF_BORDER)
371 		XSetWindowBorderWidth(dpy, fwin->core->window, scr->frame_border_width);
372 	else
373 		XSetWindowBorderWidth(dpy, fwin->core->window, 0);
374 
375 	/* setup object descriptors */
376 	if (fwin->titlebar) {
377 		fwin->titlebar->descriptor.handle_expose = handleExpose;
378 		fwin->titlebar->descriptor.parent = fwin;
379 		fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
380 		fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
381 	}
382 
383 	if (fwin->resizebar) {
384 		fwin->resizebar->descriptor.handle_expose = handleExpose;
385 		fwin->resizebar->descriptor.parent = fwin;
386 		fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
387 		fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
388 	}
389 
390 	if (fwin->left_button) {
391 		fwin->left_button->descriptor.handle_expose = handleButtonExpose;
392 		fwin->left_button->descriptor.parent = fwin;
393 		fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
394 		fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
395 	}
396 
397 #ifdef XKB_BUTTON_HINT
398 	if (fwin->language_button) {
399 		fwin->language_button->descriptor.handle_expose = handleButtonExpose;
400 		fwin->language_button->descriptor.parent = fwin;
401 		fwin->language_button->descriptor.parent_type = WCLASS_FRAME;
402 		fwin->language_button->descriptor.handle_mousedown = buttonMouseDown;
403 	}
404 #endif
405 
406 	if (fwin->right_button) {
407 		fwin->right_button->descriptor.parent = fwin;
408 		fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
409 		fwin->right_button->descriptor.handle_expose = handleButtonExpose;
410 		fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
411 	}
412 
413 	checkTitleSize(fwin);
414 
415 	allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_border_color), &fwin->border_pixel);
416 	allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_focused_border_color), &fwin->focused_border_pixel);
417 	allocFrameBorderPixel(fwin->colormap, WMGetColorRGBDescription(scr->frame_selected_border_color), &fwin->selected_border_pixel);
418 
419 	if (flags & WFF_SELECTED) {
420 		if (fwin->selected_border_pixel)
421 			XSetWindowBorder(dpy, fwin->core->window, *fwin->selected_border_pixel);
422 	}
423 	else {
424 		if (fwin->flags.state == WS_FOCUSED) {
425 			if (fwin->focused_border_pixel)
426 				XSetWindowBorder(dpy, fwin->core->window, *fwin->focused_border_pixel);
427 		} else {
428 			if (fwin->border_pixel)
429 				XSetWindowBorder(dpy, fwin->core->window, *fwin->border_pixel);
430 		}
431 	}
432 }
433 
wFrameWindowDestroy(WFrameWindow * fwin)434 void wFrameWindowDestroy(WFrameWindow * fwin)
435 {
436 	int i;
437 
438 	if (fwin->left_button)
439 		wCoreDestroy(fwin->left_button);
440 
441 #ifdef XKB_BUTTON_HINT
442 	if (fwin->language_button)
443 		wCoreDestroy(fwin->language_button);
444 #endif
445 
446 	if (fwin->right_button)
447 		wCoreDestroy(fwin->right_button);
448 
449 	if (fwin->resizebar)
450 		wCoreDestroy(fwin->resizebar);
451 
452 	if (fwin->titlebar)
453 		wCoreDestroy(fwin->titlebar);
454 
455 	RemoveFromStackList(fwin->core);
456 
457 	wCoreDestroy(fwin->core);
458 
459 	if (fwin->title)
460 		wfree(fwin->title);
461 
462 	for (i = 0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
463 		FREE_PIXMAP(fwin->title_back[i]);
464 		if (wPreferences.new_style == TS_NEW) {
465 			FREE_PIXMAP(fwin->lbutton_back[i]);
466 #ifdef XKB_BUTTON_HINT
467 			FREE_PIXMAP(fwin->languagebutton_back[i]);
468 #endif
469 			FREE_PIXMAP(fwin->rbutton_back[i]);
470 		}
471 	}
472 
473 	wfree(fwin);
474 }
475 
wFrameWindowChangeState(WFrameWindow * fwin,int state)476 void wFrameWindowChangeState(WFrameWindow * fwin, int state)
477 {
478 	if (fwin->flags.state == state)
479 		return;
480 
481 	fwin->flags.state = state;
482 	fwin->flags.need_texture_change = 1;
483 
484 	if (fwin->flags.state == WS_FOCUSED) {
485 		if (fwin->focused_border_pixel)
486 			XSetWindowBorder(dpy, fwin->core->window, *fwin->focused_border_pixel);
487 	} else {
488 		if (fwin->border_pixel)
489 			XSetWindowBorder(dpy, fwin->core->window, *fwin->border_pixel);
490 	}
491 	wFrameWindowPaint(fwin);
492 }
493 
updateTitlebar(WFrameWindow * fwin)494 static void updateTitlebar(WFrameWindow * fwin)
495 {
496 	int x, w;
497 	int theight;
498 
499 	theight = WMFontHeight(*fwin->font) + (*fwin->title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
500 
501 	if (theight > *fwin->title_max_height)
502 		theight = *fwin->title_max_height;
503 
504 	if (theight < *fwin->title_min_height)
505 		theight = *fwin->title_min_height;
506 
507 	x = 0;
508 	w = fwin->core->width + 1;
509 
510 	if (wPreferences.new_style == TS_NEW) {
511 		if (fwin->flags.hide_left_button || !fwin->left_button || fwin->flags.lbutton_dont_fit) {
512 			x = 0;
513 #ifdef XKB_BUTTON_HINT
514 			if (fwin->language_button)
515 				wCoreConfigure(fwin->language_button, 0, 0,
516 					       fwin->language_button->width, fwin->language_button->width);
517 #endif
518 		} else {
519 #ifdef XKB_BUTTON_HINT
520 			if (fwin->language_button)
521 				wCoreConfigure(fwin->language_button, fwin->left_button->width, 0,
522 					       fwin->language_button->width, fwin->language_button->width);
523 #endif
524 			x = fwin->left_button->width;
525 			w -= fwin->left_button->width;
526 		}
527 #ifdef XKB_BUTTON_HINT
528 		if (fwin->flags.hide_language_button || !fwin->language_button
529 		    || fwin->flags.languagebutton_dont_fit) {
530 		} else {
531 			x += fwin->language_button->width;
532 			w -= fwin->language_button->width;
533 		}
534 #endif
535 	}
536 #ifdef XKB_BUTTON_HINT
537 	else {
538 		int bsize = theight - 7;
539 		if (fwin->flags.hide_left_button || !fwin->left_button || fwin->flags.lbutton_dont_fit) {
540 			if (fwin->language_button)
541 				wCoreConfigure(fwin->language_button, 3, (theight - bsize) / 2,
542 					       fwin->language_button->width, fwin->language_button->width);
543 		} else {
544 			if (fwin->language_button)
545 				wCoreConfigure(fwin->language_button,
546 					       6 + fwin->left_button->width, (theight - bsize) / 2,
547 					       fwin->language_button->width, fwin->language_button->width);
548 		}
549 	}
550 #endif
551 
552 	if (wPreferences.new_style == TS_NEW) {
553 		if (!fwin->flags.hide_right_button && fwin->right_button && !fwin->flags.rbutton_dont_fit)
554 			w -= fwin->right_button->width;
555 	}
556 
557 	if (wPreferences.new_style == TS_NEW || fwin->titlebar->width != w)
558 		fwin->flags.need_texture_remake = 1;
559 
560 	wCoreConfigure(fwin->titlebar, x, 0, w, theight);
561 }
562 
wFrameWindowHideButton(WFrameWindow * fwin,int flags)563 void wFrameWindowHideButton(WFrameWindow * fwin, int flags)
564 {
565 	if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
566 		XUnmapWindow(dpy, fwin->right_button->window);
567 		fwin->flags.hide_right_button = 1;
568 	}
569 
570 	if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
571 		XUnmapWindow(dpy, fwin->left_button->window);
572 		fwin->flags.hide_left_button = 1;
573 	}
574 #ifdef XKB_BUTTON_HINT
575 	if ((flags & WFF_LANGUAGE_BUTTON) && fwin->language_button) {
576 		XUnmapWindow(dpy, fwin->language_button->window);
577 		fwin->flags.hide_language_button = 1;
578 	}
579 #endif
580 
581 	if (fwin->titlebar) {
582 		if (wPreferences.new_style == TS_NEW) {
583 			updateTitlebar(fwin);
584 		} else {
585 #ifdef XKB_BUTTON_HINT
586 			updateTitlebar(fwin);
587 #else
588 			XClearWindow(dpy, fwin->titlebar->window);
589 			wFrameWindowPaint(fwin);
590 #endif
591 		}
592 		checkTitleSize(fwin);
593 	}
594 }
595 
wFrameWindowShowButton(WFrameWindow * fwin,int flags)596 void wFrameWindowShowButton(WFrameWindow * fwin, int flags)
597 {
598 	if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button && fwin->flags.hide_right_button) {
599 
600 		if (!fwin->flags.rbutton_dont_fit)
601 			XMapWindow(dpy, fwin->right_button->window);
602 
603 		fwin->flags.hide_right_button = 0;
604 	}
605 #ifdef XKB_BUTTON_HINT
606 	if ((flags & WFF_LANGUAGE_BUTTON) && fwin->language_button && fwin->flags.hide_language_button) {
607 
608 		if (!fwin->flags.languagebutton_dont_fit)
609 			XMapWindow(dpy, fwin->language_button->window);
610 
611 		fwin->flags.hide_language_button = 0;
612 	}
613 #endif
614 
615 	if ((flags & WFF_LEFT_BUTTON) && fwin->left_button && fwin->flags.hide_left_button) {
616 
617 		if (!fwin->flags.lbutton_dont_fit)
618 			XMapWindow(dpy, fwin->left_button->window);
619 
620 		fwin->flags.hide_left_button = 0;
621 	}
622 
623 	if (fwin->titlebar) {
624 		if (wPreferences.new_style == TS_NEW) {
625 			updateTitlebar(fwin);
626 		} else {
627 			XClearWindow(dpy, fwin->titlebar->window);
628 			wFrameWindowPaint(fwin);
629 		}
630 		checkTitleSize(fwin);
631 	}
632 }
633 
634 static void
635 #ifdef XKB_BUTTON_HINT
renderTexture(WScreen * scr,WTexture * texture,int width,int height,int bwidth,int bheight,int left,int language,int right,Pixmap * title,Pixmap * lbutton,Pixmap * languagebutton,Pixmap * rbutton)636 renderTexture(WScreen * scr, WTexture * texture, int width, int height,
637 	      int bwidth, int bheight, int left, int language, int right,
638 	      Pixmap * title, Pixmap * lbutton, Pixmap * languagebutton, Pixmap * rbutton)
639 #else
640 renderTexture(WScreen * scr, WTexture * texture, int width, int height,
641 	      int bwidth, int bheight, int left, int right, Pixmap * title, Pixmap * lbutton, Pixmap * rbutton)
642 #endif
643 {
644 	RImage *img;
645 	RImage *limg, *rimg, *mimg;
646 #ifdef XKB_BUTTON_HINT
647 	RImage *timg;
648 #endif
649 	int x, w;
650 
651 	*title = None;
652 	*lbutton = None;
653 	*rbutton = None;
654 #ifdef XKB_BUTTON_HINT
655 	*languagebutton = None;
656 #endif
657 
658 	img = wTextureRenderImage(texture, width, height, WREL_FLAT);
659 	if (!img) {
660 		wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
661 		return;
662 	}
663 
664 	if (wPreferences.new_style == TS_NEW) {
665 		if (left)
666 			limg = RGetSubImage(img, 0, 0, bwidth, bheight);
667 		else
668 			limg = NULL;
669 
670 		x = 0;
671 		w = img->width;
672 
673 #ifdef XKB_BUTTON_HINT
674 		if (language)
675 			timg = RGetSubImage(img, bwidth * left, 0, bwidth, bheight);
676 		else
677 			timg = NULL;
678 #endif
679 
680 		if (limg) {
681 			RBevelImage(limg, RBEV_RAISED2);
682 			if (!RConvertImage(scr->rcontext, limg, lbutton))
683 				wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
684 
685 			x += limg->width;
686 			w -= limg->width;
687 			RReleaseImage(limg);
688 		}
689 #ifdef XKB_BUTTON_HINT
690 		if (timg) {
691 			RBevelImage(timg, RBEV_RAISED2);
692 			if (!RConvertImage(scr->rcontext, timg, languagebutton))
693 				wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
694 
695 			x += timg->width;
696 			w -= timg->width;
697 			RReleaseImage(timg);
698 		}
699 #endif
700 
701 		if (right)
702 			rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
703 		else
704 			rimg = NULL;
705 
706 		if (rimg) {
707 			RBevelImage(rimg, RBEV_RAISED2);
708 			if (!RConvertImage(scr->rcontext, rimg, rbutton))
709 				wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
710 
711 			w -= rimg->width;
712 			RReleaseImage(rimg);
713 		}
714 
715 		if (w != width) {
716 			mimg = RGetSubImage(img, x, 0, w, img->height);
717 			RBevelImage(mimg, RBEV_RAISED2);
718 
719 			if (!RConvertImage(scr->rcontext, mimg, title))
720 				wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
721 
722 			RReleaseImage(mimg);
723 		} else {
724 			RBevelImage(img, RBEV_RAISED2);
725 
726 			if (!RConvertImage(scr->rcontext, img, title))
727 				wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
728 		}
729 	} else {
730 		RBevelImage(img, RBEV_RAISED2);
731 
732 		if (!RConvertImage(scr->rcontext, img, title))
733 			wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
734 	}
735 
736 	RReleaseImage(img);
737 }
738 
739 static void
renderResizebarTexture(WScreen * scr,WTexture * texture,int width,int height,int cwidth,Pixmap * pmap)740 renderResizebarTexture(WScreen * scr, WTexture * texture, int width, int height, int cwidth, Pixmap * pmap)
741 {
742 	RImage *img;
743 	RColor light;
744 	RColor dark;
745 
746 	*pmap = None;
747 
748 	img = wTextureRenderImage(texture, width, height, WREL_FLAT);
749 	if (!img) {
750 		wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
751 		return;
752 	}
753 
754 	light.alpha = 0;
755 	light.red = light.green = light.blue = 80;
756 
757 	dark.alpha = 0;
758 	dark.red = dark.green = dark.blue = 40;
759 
760 	ROperateLine(img, RSubtractOperation, 0, 0, width - 1, 0, &dark);
761 	ROperateLine(img, RAddOperation, 0, 1, width - 1, 1, &light);
762 
763 	ROperateLine(img, RSubtractOperation, cwidth, 2, cwidth, height - 1, &dark);
764 	ROperateLine(img, RAddOperation, cwidth + 1, 2, cwidth + 1, height - 1, &light);
765 
766 	if (width > 1)
767 		ROperateLine(img, RSubtractOperation, width - cwidth - 2, 2,
768 			     width - cwidth - 2, height - 1, &dark);
769 	ROperateLine(img, RAddOperation, width - cwidth - 1, 2, width - cwidth - 1, height - 1, &light);
770 
771 #ifdef SHADOW_RESIZEBAR
772 	ROperateLine(img, RAddOperation, 0, 1, 0, height - 1, &light);
773 	ROperateLine(img, RSubtractOperation, width - 1, 1, width - 1, height - 1, &dark);
774 	ROperateLine(img, RSubtractOperation, 0, height - 1, width - 1, height - 1, &dark);
775 #endif				/* SHADOW_RESIZEBAR */
776 
777 	if (!RConvertImage(scr->rcontext, img, pmap))
778 		wwarning(_("error rendering image: %s"), RMessageForError(RErrorCode));
779 
780 	RReleaseImage(img);
781 }
782 
updateTexture(WFrameWindow * fwin)783 static void updateTexture(WFrameWindow * fwin)
784 {
785 	int i;
786 	unsigned long pixel;
787 
788 	i = fwin->flags.state;
789 	if (fwin->titlebar) {
790 		if (fwin->title_texture[i]->any.type != WTEX_SOLID) {
791 			XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window, fwin->title_back[i]);
792 			if (wPreferences.new_style == TS_NEW) {
793 				if (fwin->left_button && fwin->lbutton_back[i])
794 					XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
795 								   fwin->lbutton_back[i]);
796 
797 #ifdef XKB_BUTTON_HINT
798 				if (fwin->language_button && fwin->languagebutton_back[i])
799 					XSetWindowBackgroundPixmap(dpy, fwin->language_button->window,
800 								   fwin->languagebutton_back[i]);
801 #endif
802 
803 				if (fwin->right_button && fwin->rbutton_back[i])
804 					XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
805 								   fwin->rbutton_back[i]);
806 			}
807 		} else {
808 			pixel = fwin->title_texture[i]->solid.normal.pixel;
809 			XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
810 			if (wPreferences.new_style == TS_NEW) {
811 				if (fwin->left_button)
812 					XSetWindowBackground(dpy, fwin->left_button->window, pixel);
813 #ifdef XKB_BUTTON_HINT
814 				if (fwin->language_button)
815 					XSetWindowBackground(dpy, fwin->language_button->window, pixel);
816 #endif
817 				if (fwin->right_button)
818 					XSetWindowBackground(dpy, fwin->right_button->window, pixel);
819 			}
820 		}
821 		XClearWindow(dpy, fwin->titlebar->window);
822 
823 		if (fwin->left_button) {
824 			XClearWindow(dpy, fwin->left_button->window);
825 			handleButtonExpose(&fwin->left_button->descriptor, NULL);
826 		}
827 #ifdef XKB_BUTTON_HINT
828 		if (fwin->language_button) {
829 			XClearWindow(dpy, fwin->language_button->window);
830 			handleButtonExpose(&fwin->language_button->descriptor, NULL);
831 		}
832 #endif
833 		if (fwin->right_button) {
834 			XClearWindow(dpy, fwin->right_button->window);
835 			handleButtonExpose(&fwin->right_button->descriptor, NULL);
836 		}
837 	}
838 }
839 
remakeTexture(WFrameWindow * fwin,int state)840 static void remakeTexture(WFrameWindow * fwin, int state)
841 {
842 	Pixmap pmap, lpmap, rpmap;
843 #ifdef XKB_BUTTON_HINT
844 	Pixmap tpmap;
845 #endif
846 
847 	if (fwin->title_texture[state] && fwin->titlebar) {
848 		FREE_PIXMAP(fwin->title_back[state]);
849 		if (wPreferences.new_style == TS_NEW) {
850 			FREE_PIXMAP(fwin->lbutton_back[state]);
851 			FREE_PIXMAP(fwin->rbutton_back[state]);
852 #ifdef XKB_BUTTON_HINT
853 			FREE_PIXMAP(fwin->languagebutton_back[state]);
854 #endif
855 		}
856 
857 		if (fwin->title_texture[state]->any.type != WTEX_SOLID) {
858 			int left, right;
859 			int width;
860 #ifdef XKB_BUTTON_HINT
861 			int language;
862 #endif
863 
864 			/* eventually surrounded by if new_style */
865 			left = fwin->left_button && !fwin->flags.hide_left_button && !fwin->flags.lbutton_dont_fit;
866 #ifdef XKB_BUTTON_HINT
867 			language = fwin->language_button && !fwin->flags.hide_language_button
868 			    && !fwin->flags.languagebutton_dont_fit;
869 #endif
870 			right = fwin->right_button && !fwin->flags.hide_right_button
871 			    && !fwin->flags.rbutton_dont_fit;
872 
873 			width = fwin->core->width + 1;
874 
875 #ifdef XKB_BUTTON_HINT
876 			renderTexture(fwin->screen_ptr, fwin->title_texture[state],
877 				      width, fwin->titlebar->height,
878 				      fwin->titlebar->height, fwin->titlebar->height,
879 				      left, language, right, &pmap, &lpmap, &tpmap, &rpmap);
880 #else
881 			renderTexture(fwin->screen_ptr, fwin->title_texture[state],
882 				      width, fwin->titlebar->height,
883 				      fwin->titlebar->height, fwin->titlebar->height,
884 				      left, right, &pmap, &lpmap, &rpmap);
885 #endif
886 
887 			fwin->title_back[state] = pmap;
888 			if (wPreferences.new_style == TS_NEW) {
889 				fwin->lbutton_back[state] = lpmap;
890 				fwin->rbutton_back[state] = rpmap;
891 #ifdef XKB_BUTTON_HINT
892 				fwin->languagebutton_back[state] = tpmap;
893 #endif
894 			}
895 		}
896 	}
897 	if (fwin->resizebar_texture && fwin->resizebar_texture[0]
898 	    && fwin->resizebar && state == 0) {
899 
900 		FREE_PIXMAP(fwin->resizebar_back[0]);
901 
902 		if (fwin->resizebar_texture[0]->any.type != WTEX_SOLID) {
903 
904 			renderResizebarTexture(fwin->screen_ptr,
905 					       fwin->resizebar_texture[0],
906 					       fwin->resizebar->width,
907 					       fwin->resizebar->height, fwin->resizebar_corner_width, &pmap);
908 
909 			fwin->resizebar_back[0] = pmap;
910 		}
911 
912 		/* this part should be in updateTexture() */
913 		if (fwin->resizebar_texture[0]->any.type != WTEX_SOLID)
914 			XSetWindowBackgroundPixmap(dpy, fwin->resizebar->window, fwin->resizebar_back[0]);
915 		else
916 			XSetWindowBackground(dpy, fwin->resizebar->window,
917 					     fwin->resizebar_texture[0]->solid.normal.pixel);
918 
919 		XClearWindow(dpy, fwin->resizebar->window);
920 	}
921 }
922 
wFrameWindowPaint(WFrameWindow * fwin)923 void wFrameWindowPaint(WFrameWindow * fwin)
924 {
925 	WScreen *scr = fwin->screen_ptr;
926 	int state;
927 
928 	state = fwin->flags.state;
929 
930 	if (fwin->flags.is_client_window_frame)
931 		fwin->flags.justification = wPreferences.title_justification;
932 
933 	if (fwin->flags.need_texture_remake) {
934 		int i;
935 
936 		fwin->flags.need_texture_remake = 0;
937 		fwin->flags.need_texture_change = 0;
938 
939 		if (fwin->flags.single_texture) {
940 			remakeTexture(fwin, 0);
941 			updateTexture(fwin);
942 		} else {
943 			/* first render the texture for the current state... */
944 			remakeTexture(fwin, state);
945 			/* ... and paint it */
946 			updateTexture(fwin);
947 
948 			for (i = 0; i < 3; i++) {
949 				if (i != state)
950 					remakeTexture(fwin, i);
951 			}
952 		}
953 	}
954 
955 	if (fwin->flags.need_texture_change) {
956 		fwin->flags.need_texture_change = 0;
957 
958 		updateTexture(fwin);
959 	}
960 
961 	if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
962 	    && fwin->title_texture[state]->any.type == WTEX_SOLID) {
963 		wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
964 			   fwin->titlebar->height, (WTexSolid *) fwin->title_texture[state], WREL_RAISED);
965 	}
966 
967 	if (fwin->resizebar && !fwin->flags.repaint_only_titlebar
968 	    && fwin->resizebar_texture[0]->any.type == WTEX_SOLID) {
969 		Window win;
970 		int w, h;
971 		int cw;
972 		GC light_gc, dim_gc;
973 		WTexSolid *texture = (WTexSolid *) fwin->resizebar_texture[0];
974 
975 		w = fwin->resizebar->width;
976 		h = fwin->resizebar->height;
977 		cw = fwin->resizebar_corner_width;
978 		light_gc = texture->light_gc;
979 		dim_gc = texture->dim_gc;
980 		win = fwin->resizebar->window;
981 
982 		XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
983 		XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
984 
985 		XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
986 		XDrawLine(dpy, win, light_gc, cw + 1, 2, cw + 1, h);
987 
988 		XDrawLine(dpy, win, dim_gc, w - cw - 2, 2, w - cw - 2, h);
989 		XDrawLine(dpy, win, light_gc, w - cw - 1, 2, w - cw - 1, h);
990 
991 #ifdef SHADOW_RESIZEBAR
992 		XDrawLine(dpy, win, light_gc, 0, 1, 0, h - 1);
993 		XDrawLine(dpy, win, dim_gc, w - 1, 2, w - 1, h - 1);
994 		XDrawLine(dpy, win, dim_gc, 1, h - 1, cw, h - 1);
995 		XDrawLine(dpy, win, dim_gc, cw + 2, h - 1, w - cw - 2, h - 1);
996 		XDrawLine(dpy, win, dim_gc, w - cw, h - 1, w - 1, h - 1);
997 #endif				/* SHADOW_RESIZEBAR */
998 	}
999 
1000 	if (fwin->titlebar && !fwin->flags.repaint_only_resizebar) {
1001 		int x, y, w, h;
1002 		int lofs = 6, rofs = 6;
1003 		int titlelen;
1004 		int allButtons = 1;
1005 
1006 		if (!wPreferences.new_style == TS_NEW) {
1007 			if (fwin->left_button && !fwin->flags.hide_left_button && !fwin->flags.lbutton_dont_fit)
1008 				lofs += fwin->left_button->width + 3;
1009 			else
1010 				allButtons = 0;
1011 
1012 #ifdef XKB_BUTTON_HINT
1013 			if (fwin->language_button && !fwin->flags.hide_language_button
1014 			    && !fwin->flags.languagebutton_dont_fit)
1015 				lofs += fwin->language_button->width;
1016 			else
1017 				allButtons = 0;
1018 #endif
1019 
1020 			if (fwin->right_button && !fwin->flags.hide_right_button && !fwin->flags.rbutton_dont_fit)
1021 				rofs += fwin->right_button->width + 3;
1022 			else
1023 				allButtons = 0;
1024 		}
1025 #ifdef XKB_BUTTON_HINT
1026 		fwin->languagebutton_image = scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
1027 #endif
1028 
1029 		if (fwin->title) {
1030 			Drawable buf;
1031 			char *title;
1032 
1033 			title = ShrinkString(*fwin->font, fwin->title, fwin->titlebar->width - lofs - rofs);
1034 			titlelen = strlen(title);
1035 			w = WMWidthOfString(*fwin->font, title, titlelen);
1036 
1037 			switch (fwin->flags.justification) {
1038 			case WTJ_LEFT:
1039 				x = lofs;
1040 				break;
1041 
1042 			case WTJ_RIGHT:
1043 				x = fwin->titlebar->width - w - rofs;
1044 				break;
1045 
1046 			default:
1047 				if (!allButtons)
1048 					x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
1049 				else
1050 					x = (fwin->titlebar->width - w) / 2;
1051 				break;
1052 			}
1053 
1054 			y = *fwin->title_clearance + TITLEBAR_EXTEND_SPACE;
1055 			h = WMFontHeight(*fwin->font);
1056 
1057 			if (y*2 + h > *fwin->title_max_height)
1058 				y = (*fwin->title_max_height - h) / 2;
1059 
1060 			if (y*2 + h < *fwin->title_min_height)
1061 				y = (*fwin->title_min_height - h) / 2;
1062 
1063 			/* We use a w+2 buffer to have an extra pixel on the left and
1064 			 * another one on the right. This is because for some odd reason,
1065 			 * sometimes when using AA fonts (when libfreetype2 is compiled
1066 			 * with bytecode interpreter turned off), some fonts are drawn
1067 			 * starting from x = -1 not from 0 as requested. Observed with
1068 			 * capital A letter on the bold 'trebuchet ms' font. -Dan
1069 			 */
1070 			buf = XCreatePixmap(dpy, fwin->titlebar->window, w + 2, h, scr->w_depth);
1071 
1072 			XSetClipMask(dpy, scr->copy_gc, None);
1073 
1074 			if (fwin->title_texture[state]->any.type != WTEX_SOLID) {
1075 				XCopyArea(dpy, fwin->title_back[state], buf, scr->copy_gc,
1076 					  x - 1, y, w + 2, h, 0, 0);
1077 			} else {
1078 				XSetForeground(dpy, scr->copy_gc, fwin->title_texture[state]->solid.normal.pixel);
1079 				XFillRectangle(dpy, buf, scr->copy_gc, 0, 0, w + 2, h);
1080 			}
1081 
1082 			/*XDrawRectangle(dpy, buf, WMColorGC(scr->white),1,0,w,h-1); */
1083 			WMDrawString(scr->wmscreen, buf, fwin->title_color[state],
1084 				     *fwin->font, 1, 0, title, titlelen);
1085 
1086 			XCopyArea(dpy, buf, fwin->titlebar->window, scr->copy_gc, 0, 0, w + 2, h, x - 1, y);
1087 
1088 			XFreePixmap(dpy, buf);
1089 
1090 			wfree(title);
1091 		}
1092 
1093 		if (fwin->left_button)
1094 			handleButtonExpose(&fwin->left_button->descriptor, NULL);
1095 		if (fwin->right_button)
1096 			handleButtonExpose(&fwin->right_button->descriptor, NULL);
1097 #ifdef XKB_BUTTON_HINT
1098 		if (fwin->language_button)
1099 			handleButtonExpose(&fwin->language_button->descriptor, NULL);
1100 #endif
1101 	}
1102 }
1103 
reconfigure(WFrameWindow * fwin,int x,int y,int width,int height,Bool dontMove)1104 static void reconfigure(WFrameWindow * fwin, int x, int y, int width, int height, Bool dontMove)
1105 {
1106 	int k = (wPreferences.new_style == TS_NEW ? 4 : 3);
1107 	int resizedHorizontally = 0;
1108 
1109 	if (dontMove)
1110 		XResizeWindow(dpy, fwin->core->window, width, height);
1111 	else
1112 		XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
1113 
1114 	if (fwin->core->width != width) {
1115 		fwin->flags.need_texture_remake = 1;
1116 		resizedHorizontally = 1;
1117 	}
1118 
1119 	fwin->core->width = width;
1120 	fwin->core->height = height;
1121 
1122 	if (fwin->titlebar && resizedHorizontally) {
1123 		/* Check if the titlebar is wide enough to hold the buttons.
1124 		 * Temporarily remove them if can't
1125 		 */
1126 		if (fwin->left_button) {
1127 			if (width < fwin->top_width * k && !fwin->flags.lbutton_dont_fit) {
1128 				if (!fwin->flags.hide_left_button)
1129 					XUnmapWindow(dpy, fwin->left_button->window);
1130 
1131 				fwin->flags.lbutton_dont_fit = 1;
1132 			} else if (width >= fwin->top_width * k && fwin->flags.lbutton_dont_fit) {
1133 				if (!fwin->flags.hide_left_button)
1134 					XMapWindow(dpy, fwin->left_button->window);
1135 
1136 				fwin->flags.lbutton_dont_fit = 0;
1137 			}
1138 		}
1139 #ifdef XKB_BUTTON_HINT
1140 		if (fwin->language_button) {
1141 			if (width < fwin->top_width * k && !fwin->flags.languagebutton_dont_fit) {
1142 				if (!fwin->flags.hide_language_button)
1143 					XUnmapWindow(dpy, fwin->language_button->window);
1144 
1145 				fwin->flags.languagebutton_dont_fit = 1;
1146 			} else if (width >= fwin->top_width * k && fwin->flags.languagebutton_dont_fit) {
1147 				if (!fwin->flags.hide_language_button)
1148 					XMapWindow(dpy, fwin->language_button->window);
1149 
1150 				fwin->flags.languagebutton_dont_fit = 0;
1151 			}
1152 		}
1153 #endif
1154 
1155 		if (fwin->right_button) {
1156 			if (width < fwin->top_width * 2 && !fwin->flags.rbutton_dont_fit) {
1157 				if (!fwin->flags.hide_right_button)
1158 					XUnmapWindow(dpy, fwin->right_button->window);
1159 
1160 				fwin->flags.rbutton_dont_fit = 1;
1161 			} else if (width >= fwin->top_width * 2 && fwin->flags.rbutton_dont_fit) {
1162 				if (!fwin->flags.hide_right_button)
1163 					XMapWindow(dpy, fwin->right_button->window);
1164 
1165 				fwin->flags.rbutton_dont_fit = 0;
1166 			}
1167 		}
1168 
1169 		if (wPreferences.new_style == TS_NEW) {
1170 			if (fwin->right_button)
1171 				XMoveWindow(dpy, fwin->right_button->window,
1172 					    width - fwin->right_button->width + 1, 0);
1173 		} else {
1174 			if (fwin->right_button)
1175 				XMoveWindow(dpy, fwin->right_button->window,
1176 					    width - fwin->right_button->width - 3,
1177 					    (fwin->titlebar->height - fwin->right_button->height) / 2);
1178 		}
1179 		updateTitlebar(fwin);
1180 		checkTitleSize(fwin);
1181 	}
1182 
1183 	if (fwin->resizebar) {
1184 		wCoreConfigure(fwin->resizebar, 0,
1185 			       fwin->core->height - fwin->resizebar->height,
1186 			       fwin->core->width, fwin->resizebar->height);
1187 
1188 		fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
1189 		if (fwin->core->width < RESIZEBAR_CORNER_WIDTH * 2 + RESIZEBAR_MIN_WIDTH)
1190 			fwin->resizebar_corner_width = fwin->core->width / 2;
1191 	}
1192 }
1193 
wFrameWindowConfigure(WFrameWindow * fwin,int x,int y,int width,int height)1194 void wFrameWindowConfigure(WFrameWindow * fwin, int x, int y, int width, int height)
1195 {
1196 	reconfigure(fwin, x, y, width, height, False);
1197 }
1198 
wFrameWindowResize(WFrameWindow * fwin,int width,int height)1199 void wFrameWindowResize(WFrameWindow * fwin, int width, int height)
1200 {
1201 	reconfigure(fwin, 0, 0, width, height, True);
1202 }
1203 
wFrameWindowChangeTitle(WFrameWindow * fwin,const char * new_title)1204 int wFrameWindowChangeTitle(WFrameWindow *fwin, const char *new_title)
1205 {
1206 	if (new_title == NULL)
1207 		return 0;
1208 
1209 	/* check if the title is the same as before */
1210 	if (fwin->title) {
1211 		if (strcmp(fwin->title, new_title) == 0)
1212 			return 0;
1213 	}
1214 
1215 	if (fwin->title)
1216 		wfree(fwin->title);
1217 
1218 	fwin->title = wstrdup(new_title);
1219 
1220 	if (fwin->titlebar) {
1221 		XClearWindow(dpy, fwin->titlebar->window);
1222 
1223 		wFrameWindowPaint(fwin);
1224 	}
1225 	checkTitleSize(fwin);
1226 
1227 	return 1;
1228 }
1229 
1230 #ifdef XKB_BUTTON_HINT
wFrameWindowUpdateLanguageButton(WFrameWindow * fwin)1231 void wFrameWindowUpdateLanguageButton(WFrameWindow * fwin)
1232 {
1233 	paintButton(fwin->language_button, fwin->title_texture[fwin->flags.state],
1234 		    WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->languagebutton_image, True);
1235 }
1236 #endif				/* XKB_BUTTON_HINT */
1237 
1238 /*********************************************************************/
1239 
handleExpose(WObjDescriptor * desc,XEvent * event)1240 static void handleExpose(WObjDescriptor * desc, XEvent * event)
1241 {
1242 	WFrameWindow *fwin = (WFrameWindow *) desc->parent;
1243 
1244 	if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
1245 		fwin->flags.repaint_only_titlebar = 1;
1246 	if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
1247 		fwin->flags.repaint_only_resizebar = 1;
1248 	wFrameWindowPaint(fwin);
1249 	fwin->flags.repaint_only_titlebar = 0;
1250 	fwin->flags.repaint_only_resizebar = 0;
1251 }
1252 
checkTitleSize(WFrameWindow * fwin)1253 static void checkTitleSize(WFrameWindow * fwin)
1254 {
1255 	int width;
1256 
1257 	if (!fwin->title) {
1258 		fwin->flags.incomplete_title = 0;
1259 		return;
1260 	}
1261 
1262 	if (!fwin->titlebar) {
1263 		fwin->flags.incomplete_title = 1;
1264 		return;
1265 	} else {
1266 		width = fwin->titlebar->width - 6 - 6;
1267 	}
1268 
1269 	if (!wPreferences.new_style == TS_NEW) {
1270 		if (fwin->left_button && !fwin->flags.hide_left_button && !fwin->flags.lbutton_dont_fit)
1271 			width -= fwin->left_button->width + 3;
1272 
1273 #ifdef XKB_BUTTON_HINT
1274 		if (fwin->language_button && !fwin->flags.hide_language_button
1275 		    && !fwin->flags.languagebutton_dont_fit)
1276 			width -= fwin->language_button->width + 3;
1277 #endif
1278 
1279 		if (fwin->right_button && !fwin->flags.hide_right_button && !fwin->flags.rbutton_dont_fit)
1280 			width -= fwin->right_button->width + 3;
1281 	}
1282 
1283 	if (WMWidthOfString(*fwin->font, fwin->title, strlen(fwin->title)) > width)
1284 		fwin->flags.incomplete_title = 1;
1285 	else
1286 		fwin->flags.incomplete_title = 0;
1287 }
1288 
paintButton(WCoreWindow * button,WTexture * texture,unsigned long color,WPixmap * image,int pushed)1289 static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long color, WPixmap * image, int pushed)
1290 {
1291 	WScreen *scr = button->screen_ptr;
1292 	GC copy_gc = scr->copy_gc;
1293 	int x = 0, y = 0, d = 0;
1294 	int left = 0, width = 0;
1295 
1296 	/* setup stuff according to the state */
1297 	if (pushed) {
1298 		if (image) {
1299 			if (image->width >= image->height * 2) {
1300 				/* the image contains 2 pictures: the second is for the
1301 				 * pushed state */
1302 				width = image->width / 2;
1303 				left = image->width / 2;
1304 			} else {
1305 				width = image->width;
1306 			}
1307 		}
1308 		XSetClipMask(dpy, copy_gc, None);
1309 		if (wPreferences.new_style == TS_NEXT)
1310 			XSetForeground(dpy, copy_gc, scr->black_pixel);
1311 		else
1312 			XSetForeground(dpy, copy_gc, scr->white_pixel);
1313 
1314 		d = 1;
1315 		if (wPreferences.new_style == TS_NEW) {
1316 			XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width - 1, button->height - 1);
1317 			XSetForeground(dpy, copy_gc, scr->black_pixel);
1318 			XDrawRectangle(dpy, button->window, copy_gc, 0, 0, button->width - 1, button->height - 1);
1319 		} else if (wPreferences.new_style == TS_OLD) {
1320 			XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
1321 			XSetForeground(dpy, copy_gc, scr->black_pixel);
1322 			XDrawRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
1323 		} else {
1324 			XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width-3, button->height-3);
1325 			XSetForeground(dpy, copy_gc, scr->black_pixel);
1326 			XDrawRectangle(dpy, button->window, copy_gc, 0, 0, button->width-3, button->height-3);
1327 		}
1328 	} else {
1329 		XClearWindow(dpy, button->window);
1330 
1331 		if (image) {
1332 			if (image->width >= image->height * 2)
1333 				width = image->width / 2;
1334 			else
1335 				width = image->width;
1336 		}
1337 		d = 0;
1338 
1339 		if (wPreferences.new_style == TS_NEW) {
1340 			if (texture->any.type == WTEX_SOLID || pushed)
1341 				wDrawBevel(button->window, button->width, button->height,
1342 					   (WTexSolid *) texture, WREL_RAISED);
1343 		} else {
1344 			wDrawBevel(button->window, button->width, button->height,
1345 				   scr->widget_texture, WREL_RAISED);
1346 		}
1347 	}
1348 
1349 	if (image) {
1350 		/* display image */
1351 		XSetClipMask(dpy, copy_gc, image->mask);
1352 		x = (button->width - width) / 2 + d;
1353 		y = (button->height - image->height) / 2 + d;
1354 		XSetClipOrigin(dpy, copy_gc, x - left, y);
1355 		if (!wPreferences.new_style == TS_NEW) {
1356 			XSetForeground(dpy, copy_gc, scr->black_pixel);
1357 			if (!pushed) {
1358 				if (image->depth == 1)
1359 					XCopyPlane(dpy, image->image, button->window, copy_gc,
1360 						   left, 0, width, image->height, x, y, 1);
1361 				else
1362 					XCopyArea(dpy, image->image, button->window, copy_gc,
1363 						  left, 0, width, image->height, x, y);
1364 			} else {
1365 				if (wPreferences.new_style == TS_OLD) {
1366 					XSetForeground(dpy, copy_gc, scr->dark_pixel);
1367 					XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1368 						       button->width, button->height);
1369 				} else {
1370 					XSetForeground(dpy, copy_gc, scr->black_pixel);
1371 					XCopyArea(dpy, image->image, button->window, copy_gc,
1372 						  left, 0, width, image->height, x, y);
1373 				}
1374 			}
1375 		} else {
1376 			if (pushed) {
1377 				XSetForeground(dpy, copy_gc, scr->black_pixel);
1378 			} else {
1379 				XSetForeground(dpy, copy_gc, color);
1380 				XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1381 			}
1382 			XFillRectangle(dpy, button->window, copy_gc, 0, 0, button->width, button->height);
1383 		}
1384 	}
1385 }
1386 
handleButtonExpose(WObjDescriptor * desc,XEvent * event)1387 static void handleButtonExpose(WObjDescriptor * desc, XEvent * event)
1388 {
1389 	WFrameWindow *fwin = (WFrameWindow *) desc->parent;
1390 	WCoreWindow *button = (WCoreWindow *) desc->self;
1391 
1392 	/* Parameter not used, but tell the compiler that it is ok */
1393 	(void) event;
1394 
1395 #ifdef XKB_BUTTON_HINT
1396 	if (button == fwin->language_button) {
1397 		if (wPreferences.modelock)
1398 			paintButton(button, fwin->title_texture[fwin->flags.state],
1399 				    WMColorPixel(fwin->title_color[fwin->flags.state]),
1400 				    fwin->languagebutton_image, False);
1401 	} else
1402 #endif
1403 	if (button == fwin->left_button)
1404 		paintButton(button, fwin->title_texture[fwin->flags.state],
1405 			    WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->lbutton_image, False);
1406 	else
1407 		paintButton(button, fwin->title_texture[fwin->flags.state],
1408 			    WMColorPixel(fwin->title_color[fwin->flags.state]), fwin->rbutton_image, False);
1409 }
1410 
titlebarMouseDown(WObjDescriptor * desc,XEvent * event)1411 static void titlebarMouseDown(WObjDescriptor * desc, XEvent * event)
1412 {
1413 	WFrameWindow *fwin = desc->parent;
1414 	WCoreWindow *titlebar = desc->self;
1415 
1416 	if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1417 		if (fwin->on_dblclick_titlebar)
1418 			(*fwin->on_dblclick_titlebar) (titlebar, fwin->child, event);
1419 	} else {
1420 		if (fwin->on_mousedown_titlebar)
1421 			(*fwin->on_mousedown_titlebar) (titlebar, fwin->child, event);
1422 	}
1423 }
1424 
resizebarMouseDown(WObjDescriptor * desc,XEvent * event)1425 static void resizebarMouseDown(WObjDescriptor * desc, XEvent * event)
1426 {
1427 	WFrameWindow *fwin = desc->parent;
1428 	WCoreWindow *resizebar = desc->self;
1429 
1430 	if (fwin->on_mousedown_resizebar)
1431 		(*fwin->on_mousedown_resizebar) (resizebar, fwin->child, event);
1432 }
1433 
buttonMouseDown(WObjDescriptor * desc,XEvent * event)1434 static void buttonMouseDown(WObjDescriptor * desc, XEvent * event)
1435 {
1436 	WFrameWindow *fwin = desc->parent;
1437 	WCoreWindow *button = desc->self;
1438 	WPixmap *image;
1439 	XEvent ev;
1440 	int done = 0, execute = 1;
1441 	WTexture *texture;
1442 	unsigned long pixel;
1443 	int clickButton = event->xbutton.button;
1444 
1445 	if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1446 		if (button == fwin->right_button && fwin->on_dblclick_right)
1447 			(*fwin->on_dblclick_right) (button, fwin->child, event);
1448 
1449 		return;
1450 	}
1451 
1452 	if (button == fwin->left_button)
1453 		image = fwin->lbutton_image;
1454 	else
1455 		image = fwin->rbutton_image;
1456 
1457 #ifdef XKB_BUTTON_HINT
1458 	if (button == fwin->language_button) {
1459 		if (!wPreferences.modelock)
1460 			return;
1461 		image = fwin->languagebutton_image;
1462 	}
1463 #endif
1464 
1465 	pixel = WMColorPixel(fwin->title_color[fwin->flags.state]);
1466 	texture = fwin->title_texture[fwin->flags.state];
1467 	paintButton(button, texture, pixel, image, True);
1468 
1469 	while (!done) {
1470 		WMMaskEvent(dpy, LeaveWindowMask | EnterWindowMask | ButtonReleaseMask
1471 			    | ButtonPressMask | ExposureMask, &ev);
1472 		switch (ev.type) {
1473 		case LeaveNotify:
1474 			execute = 0;
1475 			paintButton(button, texture, pixel, image, False);
1476 			break;
1477 
1478 		case EnterNotify:
1479 			execute = 1;
1480 			paintButton(button, texture, pixel, image, True);
1481 			break;
1482 
1483 		case ButtonPress:
1484 			break;
1485 
1486 		case ButtonRelease:
1487 			if (ev.xbutton.button == clickButton)
1488 				done = 1;
1489 			break;
1490 
1491 		default:
1492 			WMHandleEvent(&ev);
1493 		}
1494 	}
1495 	paintButton(button, texture, pixel, image, False);
1496 
1497 	if (execute) {
1498 		if (button == fwin->left_button) {
1499 			if (fwin->on_click_left)
1500 				(*fwin->on_click_left) (button, fwin->child, &ev);
1501 		} else if (button == fwin->right_button) {
1502 			if (fwin->on_click_right)
1503 				(*fwin->on_click_right) (button, fwin->child, &ev);
1504 		}
1505 #ifdef XKB_BUTTON_HINT
1506 		else if (button == fwin->language_button) {
1507 			if (fwin->on_click_language)
1508 				(*fwin->on_click_language) (button, fwin->child, &ev);
1509 		}
1510 #endif
1511 
1512 	}
1513 }
1514