1 /*
2  * Copyright (C) 2003 Sasha Vasko
3  * Copyright (C) 1996 Frank Fejes
4  * Copyright (C) 1996 Alfredo Kojima
5  * Copyright (C) 1995 Bo Yang
6  * Copyright (C) 1993 Robert Nation
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #define LOCAL_DEBUG
25 
26 #include "../../configure.h"
27 
28 #include "asinternals.h"
29 #include "../../libAfterConf/afterconf.h"
30 
31 /********************************************************************/
32 /* ASWindow frame decorations :                                     */
33 /********************************************************************/
34 /* window frame decoration consists of :
35   Top level window
36 	  4 canvases - one for each side :
37 		  Top or left canvas contains titlebar+ adjusen frame side+corners if any
38 		  Bottom or right canvas contains sidebar which is the same as south frame side with corners
39 		  Remaining two canvasses contain east and west frame sides only ( if any );
40 	  Canvasses surround main window and its sizes are actually the frame size.
41  *    For each frame part and title we have separate TBarData structure. ( 9 total )
42  *    In windows with vertical title we keep the orientation of canvases but turn
43  *    tbars counterclockwise 90 degrees. As The result Title tbar will be shown on FR_W canvas,
44  *    instead of FR_N canvas. Frame parts will be shown on the following canvases :
45  *      Frame part  |   Canvas
46  *    --------------+-----------
47  *      FR_N            FR_W
48  *      FR_NE           FR_W
49  *      FR_E            FR_N
50  *      FR_SE           FR_E
51  *      FR_S            FR_E
52  *      FR_SW           FR_E
53  *      FR_W            FR_S
54  *      FR_NW           FR_W
55  *
56  *      That has to be taken on account whenever we have to associate tbars and canvases,
57  *      like in moving/resizing, redrawing, hiliting, pressing and context lookup
58  *
59  * Icon is drawn on one or two canvases. If separate button titles are selected and Icon title
60  * is allowed for this style, then separate canvas will be created for the titlebar.
61  * Respectively icon_title_canvas will be different then icon_canvas. In all other cases
62  * Icon_title_canvas will be the same as icon_canvas.
63  */
64 
65 static int NormalX, NormalY;
66 static unsigned int NormalWidth, NormalHeight;
67 /* Mirror Note :
68  *
69  * For the purpose of sizing/placing left and right sides and corners - we employ somewhat
70  * twisted logic - we mirror sides over lt2rb diagonal in case of
71  * vertical title orientation. That allows us to apply simple x/y switching instead of complex
72  * calculations. Note that we only do that for placement purposes. Contexts and images are
73  * still taken from MyFrame parts as if it was rotated counterclockwise instead of mirrored.
74  */
75 
76 ASOrientation HorzOrientation = {
77 	{C_FrameN, C_FrameE, C_FrameS, C_FrameW, C_FrameNW, C_FrameNE, C_FrameSW,
78 	 C_FrameSE},
79 	{FR_N, FR_E, FR_S, FR_W, FR_NW, FR_NE, FR_SW, FR_SE},
80 /*      N     E     S     W     NW    NE    SW    SE    TITLE */
81 	{FR_N, FR_E, FR_S, FR_W, FR_N, FR_N, FR_S, FR_S, FR_N},
82 	FR_N,
83 	{FR_NW, FR_NE},
84 	{FR_NW, FR_NE},
85 	FR_S,
86 	{FR_SW, FR_SE},
87 	{FR_SW, FR_SE},
88 	FR_W, FR_E,
89 	FR_W, FR_E,
90 	MYFRAME_HOR_MASK,
91 	TBTN_ORDER_L2R, TBTN_ORDER_L2R,
92 	&NormalX, &NormalY, &NormalWidth, &NormalHeight,
93 	&NormalX, &NormalY, &NormalWidth, &NormalHeight,
94 	0,
95 	{0, 1, 2, 3, 4, 5, 6},
96 	{0, 0, 0, 0, 0, 0, 0}
97 };
98 
99 ASOrientation VertOrientation = {
100 	{C_FrameW, C_FrameN, C_FrameE, C_FrameS, C_FrameSW, C_FrameNW, C_FrameSE,
101 	 C_FrameNE},
102 	{FR_W, FR_N, FR_E, FR_S, FR_SW, FR_NW, FR_SE, FR_NE},
103 /*      N     E     S     W     NW    NE    SW    SE    TITLE */
104 	{FR_N, FR_E, FR_S, FR_W, FR_W, FR_E, FR_W, FR_E, FR_W},
105 	FR_W,
106 	{FR_SW, FR_NW},
107 	{FR_NW, FR_SW},
108 	FR_E,
109 	{FR_SE, FR_NE},
110 	{FR_NE, FR_SE},
111 	FR_S, FR_N,
112 	FR_N, FR_S,
113 	MYFRAME_VERT_MASK,
114 	TBTN_ORDER_B2T, TBTN_ORDER_B2T,
115 	&NormalX, &NormalY, &NormalWidth, &NormalHeight,
116 	&NormalY, &NormalX, &NormalHeight, &NormalWidth,
117 	FLIP_VERTICAL,
118 	{0, 0, 0, 0, 0, 0, 0},
119 	{7, 6, 5, 4, 3, 2, 1}
120 };
121 
get_orientation_data(ASWindow * asw)122 ASOrientation *get_orientation_data (ASWindow * asw)
123 {
124 	if (asw && asw->magic == MAGIC_ASWINDOW && asw->hints)
125 		return ASWIN_HFLAGS (asw,
126 												 AS_VerticalTitle) ? &VertOrientation :
127 				&HorzOrientation;
128 	return &HorzOrientation;
129 }
130 
131 void
compile_tbar_layout(unsigned int * tbar_layout,unsigned int * default_tbar_layout,unsigned long left_layout,unsigned long right_layout)132 compile_tbar_layout (unsigned int *tbar_layout,
133 										 unsigned int *default_tbar_layout,
134 										 unsigned long left_layout, unsigned long right_layout)
135 {
136 	int l, r;
137 
138 	Bool used[MYFRAME_TITLE_BACKS] =
139 			{ False, False, False, False, False, False, False };
140 
141 	LOCAL_DEBUG_OUT ("left_layout = %lX, right_layout = %lX", left_layout,
142 									 right_layout);
143 	for (l = 0; l < MYFRAME_TITLE_BACKS; ++l)
144 		tbar_layout[l] = -1;
145 	for (l = 0; l < MYFRAME_TITLE_SIDE_ELEMS; ++l) {
146 		int elem = MYFRAME_GetTbarLayoutElem (left_layout, l);
147 
148 		if (elem != MYFRAME_TITLE_BACK_INVALID && !used[l]) {
149 			tbar_layout[elem] = default_tbar_layout[l];
150 			used[l] = True;
151 		}
152 	}
153 	for (r = MYFRAME_TITLE_BACKS; r > MYFRAME_TITLE_SIDE_ELEMS + 1;) {
154 		int elem =
155 				MYFRAME_GetTbarLayoutElem (right_layout,
156 																	 (MYFRAME_TITLE_BACKS - r));
157 		--r;
158 		LOCAL_DEBUG_OUT ("r = %d, elem = %d, used = %d", r, elem, used[r]);
159 		if (elem != MYFRAME_TITLE_BACK_INVALID && !used[r]) {
160 			/* right layout is in reverse order ! */
161 			elem = MYFRAME_TITLE_BACKS - MYFRAME_TITLE_SIDE_ELEMS + elem;
162 			tbar_layout[elem] = default_tbar_layout[r];
163 			LOCAL_DEBUG_OUT ("right_elem %d has slot = %d", elem,
164 											 tbar_layout[elem]);
165 			used[r] = True;
166 		}
167 	}
168 
169 	tbar_layout[MYFRAME_TITLE_BACK_LBL] =
170 			default_tbar_layout[MYFRAME_TITLE_BACK_LBL];
171 	used[MYFRAME_TITLE_BACK_LBL] = True;
172 	for (l = 0; l < MYFRAME_TITLE_BACKS; ++l) {
173 		if (tbar_layout[l] == -1) {
174 			int i;
175 			int from = 0, to = MYFRAME_TITLE_SIDE_ELEMS;
176 			if (l >= MYFRAME_TITLE_SIDE_ELEMS) {
177 				from = MYFRAME_TITLE_BACK_LEFT2RIGHT (MYFRAME_TITLE_SIDE_ELEMS);
178 				to = MYFRAME_TITLE_BACKS;
179 			}
180 			LOCAL_DEBUG_OUT ("missing layout for elem %d, from = %d, to = %d", l,
181 											 from, to);
182 			for (i = from; i < to; ++i) {
183 				if (!used[i]) {
184 					LOCAL_DEBUG_OUT ("found vacant slot %d", default_tbar_layout[i]);
185 					tbar_layout[l] = default_tbar_layout[i];
186 					used[i] = True;
187 					break;
188 				}
189 			}
190 		}
191 	}
192 }
193 
194 /* this gets called when Look changes or hints changes : */
check_side_canvas(ASWindow * asw,FrameSide side,Bool required)195 static ASCanvas *check_side_canvas (ASWindow * asw, FrameSide side,
196 																		Bool required)
197 {
198 	ASCanvas *canvas = asw->frame_sides[side];
199 	Window w;
200 	LOCAL_DEBUG_CALLER_OUT ("asw = %p, side = %d, required = %d", asw, side,
201 													required);
202 	if (required) {
203 		if (canvas == NULL) {				/* create canvas here */
204 			unsigned long valuemask;
205 			XSetWindowAttributes attributes;
206 
207 			valuemask = CWBorderPixel | CWEventMask;
208 			attributes.border_pixel = Scr.asv->black_pixel;
209 			if (Scr.Feel.flags & BackingStore) {
210 				valuemask |= CWBackingStore;
211 				attributes.backing_store = WhenMapped;
212 			}
213 			attributes.event_mask = AS_CANVAS_EVENT_MASK;
214 
215 			w = create_visual_window (Scr.asv, asw->frame,
216 																0, 0, 1, 1, 0, InputOutput,
217 																valuemask, &attributes);
218 			register_aswindow (w, asw);
219 			canvas = create_ascanvas (w);
220 			LOCAL_DEBUG_OUT
221 					("++CREAT Client(%lx(%s))->side(%d)->canvas(%p)->window(%lx)",
222 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", side,
223 					 canvas, canvas->w);
224 		} else
225 			invalidate_canvas_config (canvas);
226 	} else if (canvas != NULL) {	/* destroy canvas here */
227 		w = canvas->w;
228 		LOCAL_DEBUG_OUT
229 				("--DESTR Client(%lx(%s))->side(%d)->canvas(%p)->window(%lx)",
230 				 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", side,
231 				 canvas, canvas->w);
232 		destroy_ascanvas (&canvas);
233 		destroy_registered_window (w);
234 	}
235 
236 	return (asw->frame_sides[side] = canvas);
237 }
238 
239 /* creating/destroying our main frame window : */
check_frame_canvas(ASWindow * asw,Bool required)240 static ASCanvas *check_frame_canvas (ASWindow * asw, Bool required)
241 {
242 	ASCanvas *canvas = asw->frame_canvas;
243 	Window w;
244 
245 	if (required) {
246 		if (canvas == NULL) {				/* create canvas here */
247 			unsigned long valuemask;
248 			XSetWindowAttributes attributes;
249 			int bw = 0;
250 
251 			/* create windows */
252 			valuemask = CWBorderPixel | CWCursor | CWEventMask;
253 			if (Scr.asv->visual_info.visual == DefaultVisual (dpy, Scr.screen)) {
254 				/* only if root has same depth and visual as us! */
255 				attributes.background_pixmap = ParentRelative;
256 				valuemask |= CWBackPixmap;
257 			}
258 			attributes.border_pixel = Scr.asv->black_pixel;
259 			attributes.cursor = Scr.Feel.cursors[ASCUR_Default];
260 			attributes.event_mask = AS_FRAME_EVENT_MASK;
261 
262 			if (get_flags (Scr.Feel.flags, SaveUnders)) {
263 				valuemask |= CWSaveUnder;
264 				attributes.save_under = True;
265 			}
266 			if (asw->hints && get_flags (asw->hints->flags, AS_Border))
267 				bw = asw->hints->border_width;
268 			asw->status->frame_border_width = bw;
269 			w = create_visual_window (Scr.asv,
270 																(ASWIN_DESK (asw) ==
271 																 Scr.CurrentDesk) ? Scr.Root : Scr.
272 																ServiceWin, asw->status->x, asw->status->y,
273 																asw->status->width, asw->status->height,
274 																bw, InputOutput, valuemask, &attributes);
275 			XLowerWindow (dpy, w);
276 			asw->frame = w;
277 			register_aswindow (w, asw);
278 			canvas = create_ascanvas_container (w);
279 			LOCAL_DEBUG_OUT
280 					("++CREAT Client(%lx(%s))->FRAME->canvas(%p)->window(%lx)->parent(%lx)",
281 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
282 					 canvas->w,
283 					 (ASWIN_DESK (asw) ==
284 						Scr.CurrentDesk) ? Scr.Root : Scr.ServiceWin);
285 		} else
286 			invalidate_canvas_config (canvas);
287 	} else if (canvas != NULL) {	/* destroy canvas here */
288 		w = canvas->w;
289 		LOCAL_DEBUG_OUT
290 				("--DESTR Client(%lx(%s))->FRAME->canvas(%p)->window(%lx)", asw->w,
291 				 ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
292 				 canvas->w);
293 		destroy_ascanvas (&canvas);
294 		destroy_registered_window (w);
295 	}
296 
297 	return (asw->frame_canvas = canvas);
298 }
299 
300 /* creating/destroying container canvas for our client's window : */
check_client_canvas(ASWindow * asw,Bool required)301 static ASCanvas *check_client_canvas (ASWindow * asw, Bool required)
302 {
303 	ASCanvas *canvas = asw->client_canvas;
304 	Window w;
305 
306 	if (required) {
307 		if (canvas == NULL) {				/* create canvas here */
308 			unsigned long valuemask;
309 			XSetWindowAttributes attributes;
310 
311 			if (asw->frame == None || (w = asw->w) == None)
312 				return NULL;
313 
314 			attributes.event_mask = AS_CLIENT_EVENT_MASK;
315 			if (asw->internal) {
316 				XWindowAttributes internal_attr;
317 				XGetWindowAttributes (dpy, w, &internal_attr);
318 				attributes.event_mask |= internal_attr.your_event_mask;
319 			}
320 			quietly_reparent_window (w, asw->frame, 0, 0, attributes.event_mask);
321 
322 			valuemask = (CWEventMask | CWDontPropagate);
323 			attributes.do_not_propagate_mask =
324 					ButtonPressMask | ButtonReleaseMask;
325 
326 			if (get_flags (Scr.Feel.flags, AppsBackingStore)) {
327 				valuemask |= CWBackingStore;
328 				attributes.backing_store = WhenMapped;
329 			}
330 			XChangeWindowAttributes (dpy, w, valuemask, &attributes);
331 			if (asw->internal == NULL)
332 				XAddToSaveSet (dpy, w);
333 
334 			register_aswindow (w, asw);
335 			canvas = create_ascanvas_container (w);
336 			if (ASWIN_GET_FLAGS (asw, AS_Shaped))
337 				refresh_container_shape (canvas);
338 			LOCAL_DEBUG_OUT
339 					("++CREAT Client(%lx(%s))->CLIENT->canvas(%p)->window(%lx)",
340 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
341 					 canvas->w);
342 		}
343 		/*else    invalidate_canvas_config( canvas ); */
344 	} else if (canvas != NULL) {	/* destroy canvas here */
345 		XWindowChanges xwc;					/* our withdrawn geometry */
346 		ASStatusHints withdrawn_status = { 0 };
347 		register int i = 0;
348 
349 		w = canvas->w;
350 
351 		/* calculating the withdrawn location */
352 		if (asw->status)
353 			withdrawn_status = *(asw->status);
354 
355 		xwc.border_width = withdrawn_status.border_width;
356 
357 		for (i = 0; i < FRAME_SIDES; ++i)
358 			withdrawn_status.frame_size[i] = 0;
359 		clear_flags (withdrawn_status.flags, AS_Shaded | AS_Iconic);
360 		anchor2status (&withdrawn_status, asw->hints, &(asw->anchor));
361 		xwc.x = withdrawn_status.x;
362 		xwc.y = withdrawn_status.y;
363 		xwc.width = withdrawn_status.width;
364 		xwc.height = withdrawn_status.height;
365 
366 		LOCAL_DEBUG_OUT
367 				("--DESTR Client(%lx(%s))->CLIENT->canvas(%p)->window(%lx)",
368 				 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
369 				 canvas->w);
370 		destroy_ascanvas (&canvas);
371 
372 		/*
373 		 * Prevent the receipt of an UnmapNotify in case we are simply restarting,
374 		 * since that would cause a transition to the Withdrawn state.
375 		 */
376 #if 1
377 		if ((asw->status == NULL || !get_flags (asw->status->flags, AS_Dead))
378 				&& get_parent_window (w) == asw->frame) {
379 			LOCAL_DEBUG_OUT ("reparenting client window %lX", w);
380 			if (get_flags (AfterStepState, ASS_Shutdown))
381 				quietly_reparent_window (w, Scr.Root, xwc.x, xwc.y,
382 																 AS_CLIENT_EVENT_MASK);
383 			else
384 				XReparentWindow (dpy, w, Scr.Root, xwc.x, xwc.y);
385 			/* WE have to restore window's withdrawn location now. */
386 			XConfigureWindow (dpy, w,
387 												CWX | CWY | CWWidth | CWHeight | CWBorderWidth,
388 												&xwc);
389 		}
390 		XSync (dpy, 0);
391 #endif
392 	}
393 
394 	asw->client_canvas = canvas;
395 	return canvas;
396 }
397 
398 /* creating/destroying our icon window : */
check_icon_canvas(ASWindow * asw,Bool required)399 static ASCanvas *check_icon_canvas (ASWindow * asw, Bool required)
400 {
401 	ASCanvas *canvas = asw->icon_canvas;
402 	Window w;
403 
404 	if (required) {
405 		if (canvas == NULL) {				/* create canvas here */
406 			unsigned long valuemask;
407 			XSetWindowAttributes attributes;
408 
409 			valuemask = CWBorderPixel | CWCursor | CWEventMask;
410 			attributes.border_pixel = Scr.asv->black_pixel;
411 			attributes.cursor = Scr.Feel.cursors[ASCUR_Default];
412 
413 			if ((get_flags (asw->hints->client_icon_flags, AS_ClientIcon | AS_ClientIconPixmap) != AS_ClientIcon) || asw->hints == NULL || asw->hints->icon.window == None || !get_flags (Scr.Feel.flags, KeepIconWindows)) {	/* create windows */
414 				attributes.event_mask = AS_ICON_TITLE_EVENT_MASK;
415 				w = create_visual_window (Scr.asv,
416 																	(ASWIN_DESK (asw) ==
417 																	 Scr.CurrentDesk) ? Scr.Root : Scr.
418 																	ServiceWin, -9000, -9000, 1, 1, 0,
419 																	InputOutput, valuemask, &attributes);
420 				canvas = create_ascanvas (w);
421 			} else {									/* reuse client's provided window */
422 				attributes.event_mask = AS_ICON_EVENT_MASK;
423 				w = asw->hints->icon.window;
424 				XChangeWindowAttributes (dpy, w, valuemask, &attributes);
425 				canvas = create_ascanvas_container (w);
426 			}
427 			LOCAL_DEBUG_OUT
428 					("++CREAT Client(%lx(%s))->ICON->canvas(%p)->window(%lx)",
429 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
430 					 canvas->w);
431 			register_aswindow (w, asw);
432 		} else
433 			invalidate_canvas_config (canvas);
434 	} else if (canvas != NULL) {	/* destroy canvas here */
435 		w = canvas->w;
436 		LOCAL_DEBUG_OUT
437 				("--DESTR Client(%lx(%s))->ICON->canvas(%p)->window(%lx)", asw->w,
438 				 ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
439 				 canvas->w);
440 		if (asw->icon_title_canvas == canvas)
441 			asw->icon_title_canvas = NULL;
442 		destroy_ascanvas (&canvas);
443 		if (asw->hints && asw->hints->icon.window == w)
444 			unregister_aswindow (w);
445 		else
446 			destroy_registered_window (w);
447 	}
448 	asw->icon_canvas = canvas;
449 
450 	return canvas;
451 }
452 
453 /* creating/destroying our icon title window : */
check_icon_title_canvas(ASWindow * asw,Bool required,Bool reuse_icon_canvas)454 static ASCanvas *check_icon_title_canvas (ASWindow * asw, Bool required,
455 																					Bool reuse_icon_canvas)
456 {
457 	ASCanvas *canvas = asw->icon_title_canvas;
458 	Window w;
459 
460 	if (!required) {
461 		if (canvas && canvas != asw->icon_canvas) {
462 			w = canvas->w;
463 			LOCAL_DEBUG_OUT
464 					("--DESTR Client(%lx(%s))->ICONT->canvas(%p)->window(%lx)",
465 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
466 					 canvas->w);
467 			destroy_ascanvas (&canvas);
468 			destroy_registered_window (w);
469 		}
470 	} else {											/* if( required ) */
471 
472 		if (reuse_icon_canvas)
473 			canvas = asw->icon_canvas;
474 		else if (canvas == NULL) {	/* create canvas here */
475 			unsigned long valuemask;
476 			XSetWindowAttributes attributes;
477 
478 			valuemask = CWBorderPixel | CWCursor | CWEventMask;
479 			attributes.border_pixel = Scr.asv->black_pixel;
480 			attributes.cursor = Scr.Feel.cursors[ASCUR_Default];
481 			attributes.event_mask = AS_ICON_TITLE_EVENT_MASK;
482 			/* create windows */
483 			w = create_visual_window (Scr.asv,
484 																(ASWIN_DESK (asw) ==
485 																 Scr.CurrentDesk) ? Scr.Root : Scr.
486 																ServiceWin, -9010, -9010, 1, 1, 0,
487 																InputOutput, valuemask, &attributes);
488 
489 			register_aswindow (w, asw);
490 			canvas = create_ascanvas (w);
491 			LOCAL_DEBUG_OUT
492 					("++CREAT Client(%lx(%s))->ICONT->canvas(%p)->window(%lx)",
493 					 asw->w, ASWIN_NAME (asw) ? ASWIN_NAME (asw) : "noname", canvas,
494 					 canvas->w);
495 		} else
496 			invalidate_canvas_config (canvas);
497 	}
498 
499 	asw->icon_title_canvas = canvas;
500 
501 	return canvas;
502 }
503 
504 /* pointers should point to valid values preset to 0, im.width, 0, im.height */
505 static void
geometry2slicing(ASGeometry g,int * pxs,int * pxe,int * pys,int * pye)506 geometry2slicing (ASGeometry g, int *pxs, int *pxe, int *pys, int *pye)
507 {
508 	if (get_flags (g.flags, XValue))
509 		*pxs = get_flags (g.flags, XNegative) ? *pxe + g.x : g.x;
510 	if (get_flags (g.flags, YValue))
511 		*pys = get_flags (g.flags, YNegative) ? *pye + g.y : g.y;
512 
513 	if (get_flags (g.flags, WidthValue))
514 		*pxe = *pxs + g.width;
515 	if (get_flags (g.flags, HeightValue))
516 		*pye = *pys + g.height;
517 }
518 
519 
check_tbar(ASTBarData ** tbar,Bool required,const char * mystyle_name,ASImage * img,unsigned short back_w,unsigned short back_h,int flip,ASFlagType align,ASFlagType fbevel,ASFlagType ubevel,unsigned char fcm,unsigned char ucm,int context,ASGeometry * slicing)520 static ASTBarData *check_tbar (ASTBarData ** tbar, Bool required,
521 															 const char *mystyle_name, ASImage * img,
522 															 unsigned short back_w,
523 															 unsigned short back_h, int flip,
524 															 ASFlagType align, ASFlagType fbevel,
525 															 ASFlagType ubevel, unsigned char fcm,
526 															 unsigned char ucm, int context,
527 															 ASGeometry * slicing)
528 {
529 	if (required) {
530 		if (*tbar == NULL) {
531 			*tbar = create_astbar ();
532 			LOCAL_DEBUG_OUT ("++CREAT tbar(%p)->context(%s)", *tbar,
533 											 context2text (context));
534 		} else
535 			delete_astbar_tile (*tbar, -1);
536 
537 		set_astbar_flip (*tbar, flip);
538 
539 		invalidate_astbar_style (*tbar, -1);
540 		set_astbar_style (*tbar, BAR_STATE_FOCUSED, mystyle_name);
541 		set_astbar_style (*tbar, BAR_STATE_UNFOCUSED, "default");
542 		if (img) {
543 			LOCAL_DEBUG_OUT ("adding bar icon %p %ux%u", img, img->width,
544 											 img->height);
545 			if (slicing && slicing->flags) {
546 				int xs = 0, xe = 0, ys = img->width, ye = img->height;
547 				geometry2slicing (*slicing, &xs, &xe, &ys, &ye);
548 				add_astbar_image (*tbar, 0, 0, flip, align, img, xs, xe, ys, ye);
549 			} else
550 				add_astbar_icon (*tbar, 0, 0, flip, align, img);
551 			if (back_w == 0)
552 				back_w =
553 						get_flags (flip, FLIP_VERTICAL) ? img->height : img->width;
554 			if (back_h == 0)
555 				back_h =
556 						get_flags (flip, FLIP_VERTICAL) ? img->width : img->height;
557 		}
558 
559 		set_astbar_hilite (*tbar, BAR_STATE_FOCUSED, fbevel);
560 		set_astbar_hilite (*tbar, BAR_STATE_UNFOCUSED, ubevel);
561 		set_astbar_composition_method (*tbar, BAR_STATE_FOCUSED, fcm);
562 		set_astbar_composition_method (*tbar, BAR_STATE_UNFOCUSED, ucm);
563 		set_astbar_size (*tbar, (back_w == 0) ? 1 : back_w,
564 										 (back_h == 0) ? 1 : back_h);
565 		(*tbar)->context = context;
566 	} else if (*tbar) {
567 		destroy_astbar (tbar);
568 	}
569 	return *tbar;
570 }
571 
572 /******************************************************************************/
573 /* now externally available interfaces to the above functions :               */
574 /******************************************************************************/
invalidate_window_icon(ASWindow * asw)575 void invalidate_window_icon (ASWindow * asw)
576 {
577 	if (asw)
578 		check_icon_canvas (asw, False);
579 }
580 
invalidate_window_mystyles(ASWindow * asw)581 void invalidate_window_mystyles (ASWindow * asw)
582 {
583 	int i;
584 
585 	for (i = 0; i < FRAME_PARTS; ++i)
586 		if (asw->frame_bars[i])
587 			invalidate_astbar_style (asw->frame_bars[i], -1);
588 	if (asw->tbar)
589 		invalidate_astbar_style (asw->tbar, -1);
590 	if (asw->icon_button)
591 		invalidate_astbar_style (asw->icon_button, -1);
592 	if (asw->icon_title)
593 		invalidate_astbar_style (asw->icon_title, -1);
594 }
595 
596 /***********************************************************************
597  *  grab_aswindow_buttons - grab needed buttons for all of the windows
598  *  for specified client
599  ***********************************************************************/
grab_aswindow_buttons(ASWindow * asw,Bool focused)600 void grab_aswindow_buttons (ASWindow * asw, Bool focused)
601 {
602 	if (asw) {
603 		Bool do_focus_grab = (get_flags (Scr.Feel.flags, ClickToFocus));
604 		if (do_focus_grab) {
605 			if (focused)
606 				ungrab_focus_click (asw->frame);
607 			else
608 				grab_focus_click (asw->frame);
609 		} else
610 			ungrab_window_buttons (asw->frame);
611 
612 		if (!ASWIN_GET_FLAGS (asw, AS_Dead)) {
613 			ungrab_window_buttons (asw->w);
614 			grab_window_buttons (asw->w, C_WINDOW);
615 		}
616 
617 		if (asw->icon_canvas && !ASWIN_GET_FLAGS (asw, AS_Dead)
618 				&& validate_drawable (asw->icon_canvas->w, NULL, NULL) != None) {
619 			ungrab_window_buttons (asw->icon_canvas->w);
620 			if (do_focus_grab) {
621 				if (focused)
622 					ungrab_focus_click (asw->icon_canvas->w);
623 				else
624 					grab_focus_click (asw->icon_canvas->w);
625 			}
626 			grab_window_buttons (asw->icon_canvas->w, C_ICON);
627 		}
628 
629 		if (asw->icon_title_canvas
630 				&& asw->icon_title_canvas != asw->icon_canvas) {
631 			ungrab_window_buttons (asw->icon_title_canvas->w);
632 			if (do_focus_grab) {
633 				if (focused)
634 					ungrab_focus_click (asw->icon_title_canvas->w);
635 				else
636 					grab_focus_click (asw->icon_title_canvas->w);
637 			}
638 			grab_window_buttons (asw->icon_title_canvas->w, C_ICON);
639 
640 		}
641 	}
642 	XSync (dpy, False);
643 }
644 
645 /***********************************************************************
646  *  grab_aswindow_keys - grab needed keys for the window
647  ***********************************************************************/
grab_aswindow_keys(ASWindow * asw)648 void grab_aswindow_keys (ASWindow * asw)
649 {
650 	if (AS_ASSERT (asw))
651 		return;
652 
653 	ungrab_window_keys (asw->frame);
654 	grab_window_keys (asw->frame,
655 										(C_WINDOW | C_TITLE | C_TButtonAll | C_FRAME));
656 
657 	if (asw->icon_canvas) {
658 		ungrab_window_keys (asw->icon_canvas->w);
659 		grab_window_keys (asw->icon_canvas->w, (C_ICON));
660 	}
661 	if (asw->icon_title_canvas && asw->icon_title_canvas != asw->icon_canvas) {
662 		ungrab_window_keys (asw->icon_title_canvas->w);
663 		grab_window_keys (asw->icon_title_canvas->w, (C_ICON));
664 	}
665 	XSync (dpy, False);
666 }
667 
668 
669 /* this should set up proper feel settings - grab keyboard and mouse buttons :
670  * Note: must be called after redecorate_window, since some of windows may have
671  * been created at that time.
672  */
grab_window_input(ASWindow * asw,Bool release_grab)673 void grab_window_input (ASWindow * asw, Bool release_grab)
674 {
675 	if (asw) {
676 		if (release_grab) {
677 			ungrab_window_keys (asw->frame);
678 			ungrab_window_buttons (asw->frame);
679 			if (asw->icon_canvas) {
680 				ungrab_window_keys (asw->icon_canvas->w);
681 				ungrab_window_buttons (asw->icon_canvas->w);
682 			}
683 			if (asw->icon_title_canvas
684 					&& asw->icon_title_canvas != asw->icon_canvas) {
685 				ungrab_window_keys (asw->icon_title_canvas->w);
686 				ungrab_window_buttons (asw->icon_title_canvas->w);
687 			}
688 			XSync (dpy, False);
689 		} else {
690 			grab_aswindow_buttons (asw, (Scr.Windows->focused == asw));
691 			grab_aswindow_keys (asw);
692 		}
693 	}
694 }
695 
696 /*
697  ** returns a newline delimited list of the Mouse functions bound to a
698  ** given context, in human readable form
699  */
list_functions_by_context(int context,ASHints * hints)700 char *list_functions_by_context (int context, ASHints * hints)
701 {
702 	MouseButton *btn;
703 	char *str = NULL;
704 	int allocated_bytes = 0;
705 	if (hints == NULL)
706 		return NULL;
707 	for (btn = Scr.Feel.MouseButtonRoot; btn != NULL; btn = btn->NextButton)
708 		if ((btn->Context & context)
709 				&& check_allowed_function (btn->fdata, hints)) {
710 			TermDef *fterm;
711 
712 			fterm = func2fterm (btn->fdata->func, True);
713 			if (fterm != NULL) {
714 				char *ptr;
715 
716 				if (str) {
717 					str =
718 							realloc (str, allocated_bytes + 1 + fterm->keyword_len + 32);
719 					ptr = str + allocated_bytes;
720 					*(ptr++) = '\n';
721 				} else
722 					ptr = str = safemalloc (fterm->keyword_len + 32);
723 
724 				sprintf (ptr, "%s: ", fterm->keyword);
725 				ptr += fterm->keyword_len + 2;
726 				if (btn->Modifier & ShiftMask) {
727 					strcat (ptr, "Shift+");
728 					ptr += 8;
729 				}
730 				if (btn->Modifier & ControlMask) {
731 					strcat (ptr, "Ctrl+");
732 					ptr += 7;
733 				}
734 				if (btn->Modifier & Mod1Mask) {
735 					strcat (ptr, "Meta+");
736 					ptr += 7;
737 				}
738 				sprintf (ptr, "Button %d", btn->Button);
739 				allocated_bytes = strlen (str);
740 			}
741 		}
742 	return str;
743 }
744 
745 
746 
747 /****************************************************************************
748  *
749  * Checks the function "function", and sees if it
750  * is an allowed function for window t,  according to the motif way of life.
751  * This routine is used to decide if we should refuse to perform a function.
752  *
753  ****************************************************************************/
check_allowed_function2(int func,ASHints * hints)754 int check_allowed_function2 (int func, ASHints * hints)
755 {
756 	if (func == F_NOP)
757 		return 0;
758 
759 	if (hints) {
760 		int mask = function2mask (func);
761 		if (func == F_SHADE)
762 			return get_flags (hints->flags, AS_Titlebar);
763 		else if (mask != 0)
764 			return get_flags (hints->function_mask, mask);
765 	}
766 	return 1;
767 }
768 
769 /****************************************************************************
770  *
771  * Checks the function described in menuItem mi, and sees if it
772  * is an allowed function for window Tmp_Win,
773  * according to the motif way of life.
774  *
775  * This routine is used to determine whether or not to grey out menu items.
776  *
777  ****************************************************************************/
check_allowed_function(FunctionData * fdata,ASHints * hints)778 int check_allowed_function (FunctionData * fdata, ASHints * hints)
779 {
780 	int func = fdata->func;
781 	int i;
782 	ComplexFunction *cfunc;
783 
784 	if (func != F_FUNCTION && func != F_CATEGORY)
785 		return check_allowed_function2 (func, hints);
786 
787 	if (func == F_FUNCTION) {
788 		if ((cfunc = get_complex_function (fdata->name)) == NULL)
789 			return 0;
790 
791 		for (i = 0; i < cfunc->items_num; ++i)
792 			if (cfunc->items[i].func == F_FUNCTION
793 					|| cfunc->items[i].func == F_CATEGORY) {
794 				if (check_allowed_function (&(cfunc->items[i]), hints) == 0)
795 					return 0;
796 			} else if (check_allowed_function2 (cfunc->items[i].func, hints) ==
797 								 0)
798 				return 0;
799 	} else if (func == F_CATEGORY) {
800 		if (name2desktop_category
801 				(fdata->text ? fdata->text : fdata->name, NULL) == NULL)
802 			return 0;
803 	}
804 	return 1;
805 }
806 
807 
compile_titlebuttons_mask(ASHints * hints)808 ASFlagType compile_titlebuttons_mask (ASHints * hints)
809 {
810 	ASFlagType disabled_mask = hints->disabled_buttons;
811 	ASFlagType enabled_mask = 0;
812 	int i;
813 
814 	LOCAL_DEBUG_OUT ("disabled mask from hints is 0x%lX", disabled_mask);
815 
816 	for (i = 0; i < TITLE_BUTTONS; i++) {
817 		if (Scr.Look.buttons[i].unpressed.image != NULL) {
818 			int context = Scr.Look.buttons[i].context;
819 			MouseButton *func;
820 			Bool at_least_one_enabled = False;
821 
822 			enabled_mask |= context;
823 			for (func = Scr.Feel.MouseButtonRoot; func != NULL;
824 					 func = (*func).NextButton)
825 				if ((func->Context & context) != 0)
826 					if (check_allowed_function (func->fdata, hints)) {
827 						at_least_one_enabled = True;
828 						break;
829 					}
830 			if (!at_least_one_enabled)
831 				disabled_mask |= Scr.Look.buttons[i].context;
832 		}
833 	}
834 	LOCAL_DEBUG_OUT
835 			("disabled mask(0x%lX)->enabled_mask(0x%lX)->button_mask(0x%lX)",
836 			 disabled_mask, enabled_mask, enabled_mask & (~disabled_mask));
837 
838 
839 	return enabled_mask & (~disabled_mask);
840 }
841 
842 void
estimate_titlebar_size(ASHints * hints,unsigned int * width_ret,unsigned int * height_ret)843 estimate_titlebar_size (ASHints * hints, unsigned int *width_ret,
844 												unsigned int *height_ret)
845 {
846 	unsigned int width = 0, height = 0;
847 	if (hints) {
848 		ASTBarData *tbar = create_astbar ();
849 		ASFlagType btn_mask;
850 
851 		btn_mask = compile_titlebuttons_mask (hints);
852 		tbar->h_spacing = DEFAULT_TBAR_HSPACING;
853 		tbar->v_spacing = DEFAULT_TBAR_VSPACING;
854 		/* left buttons : */
855 		add_astbar_btnblock (tbar, 0, 0, 0, NO_ALIGN,
856 												 &(Scr.Look.ordered_buttons[0]), btn_mask,
857 												 Scr.Look.button_first_right,
858 												 Scr.Look.TitleButtonXOffset[0],
859 												 Scr.Look.TitleButtonYOffset[0],
860 												 Scr.Look.TitleButtonSpacing[0], TBTN_ORDER_L2R);
861 
862 		/* label */
863 		add_astbar_label (tbar, 1, 0, 0, ALIGN_LEFT, DEFAULT_TBAR_HSPACING,
864 											DEFAULT_TBAR_VSPACING, hints->names[0],
865 											hints->names_encoding[0]);
866 		/* right buttons : */
867 		add_astbar_btnblock (tbar, 2, 0, 0, NO_ALIGN,
868 												 &(Scr.Look.
869 													 ordered_buttons[Scr.Look.button_first_right]),
870 												 btn_mask,
871 												 TITLE_BUTTONS - Scr.Look.button_first_right,
872 												 Scr.Look.TitleButtonXOffset[1],
873 												 Scr.Look.TitleButtonYOffset[1],
874 												 Scr.Look.TitleButtonSpacing[1], TBTN_ORDER_R2L);
875 
876 		set_astbar_style_ptr (tbar, BAR_STATE_UNFOCUSED,
877 													Scr.Look.MSMenu[MENU_BACK_TITLE]);
878 		set_astbar_style_ptr (tbar, BAR_STATE_FOCUSED,
879 													Scr.Look.MSMenu[MENU_BACK_HITITLE]);
880 		width = calculate_astbar_width (tbar);
881 		height = calculate_astbar_height (tbar);
882 		destroy_astbar (&tbar);
883 	}
884 	if (width_ret)
885 		*width_ret = width;
886 	if (height_ret)
887 		*height_ret = height;
888 }
889 
fix_background_align(ASFlagType align)890 inline static ASFlagType fix_background_align (ASFlagType align)
891 {
892 	ASFlagType new_align = align;
893 	/* don't ask why - simply magic :)
894 	 * Well not really - we want to disregard background size in calculations of overall
895 	 * titlebar size. Overall titlebar size is determined only by text size and button sizes.
896 	 * At the same time we would like to be able to scale backgrounds to the size of the
897 	 * titlebar
898 	 */
899 	/* clear_flags(new_align , (RESIZE_H|RESIZE_V)); */
900 	if (get_flags (new_align, RESIZE_H_SCALE))
901 		set_flags (new_align, FIT_LABEL_WIDTH);
902 	if (get_flags (new_align, RESIZE_V_SCALE))
903 		set_flags (new_align, FIT_LABEL_HEIGHT);
904 	LOCAL_DEBUG_OUT ("Fixed align from 0x%lx to 0x%lx", align, new_align);
905 	return new_align;
906 }
907 
hints2decorations(ASWindow * asw,ASHints * old_hints)908 Bool hints2decorations (ASWindow * asw, ASHints * old_hints)
909 {
910 	int i;
911 	MyFrame *frame = NULL, *old_frame = NULL;
912 	Bool has_tbar = False, had_tbar = False;
913 	Bool icon_image_changed = True;
914 	ASOrientation *od = get_orientation_data (asw);
915 	char *mystyle_name = Scr.Look.MSWindow[BACK_FOCUSED]->name;
916 	char *frame_mystyle_name = NULL;
917 	unsigned int *frame_contexts = &(od->frame_contexts[0]);
918 	Bool tbar_created = False;
919 	Bool status_changed = False;
920 
921 	LOCAL_DEBUG_CALLER_OUT ("asw(%p)->client(%lX)", asw, asw ? asw->w : 0);
922 
923 	/* 3) we need to prepare icon window : */
924 	check_icon_canvas (asw,
925 										 (ASWIN_HFLAGS (asw, AS_Icon)
926 											&& !get_flags (Scr.Feel.flags, SuppressIcons)));
927 
928 	/* 4) we need to prepare icon title window : */
929 	LOCAL_DEBUG_CALLER_OUT ("checking icon title canvas(%p)",
930 													asw->icon_title_canvas);
931 	check_icon_title_canvas (asw,
932 													 (ASWIN_HFLAGS (asw, AS_IconTitle)
933 														&& get_flags (Scr.Feel.flags, IconTitle)
934 														&& !get_flags (Scr.Feel.flags, SuppressIcons)),
935 													 !get_flags (Scr.Look.flags, SeparateButtonTitle)
936 													 && (asw->icon_canvas != NULL));
937 
938 	has_tbar = (ASWIN_HFLAGS (asw, AS_Titlebar) != 0);
939 	frame =
940 			myframe_find (ASWIN_HFLAGS (asw, AS_Frame) ? asw->hints->
941 										frame_name : NULL);
942 	if (old_hints == NULL) {
943 		had_tbar = !has_tbar;
944 		old_frame = NULL;
945 	} else {
946 		had_tbar = (get_flags (old_hints->flags, AS_Titlebar) != 0);
947 		old_frame =
948 				myframe_find (get_flags (old_hints->flags, AS_Frame) ? old_hints->
949 											frame_name : NULL);
950 	}
951 
952 	asw->frame_data = frame;
953 
954 	/* 5) we need to prepare windows for 4 frame decoration sides : */
955 	if (has_tbar != had_tbar || frame != old_frame) {
956 		LOCAL_DEBUG_OUT ("has_tbar = %d, has_top_parts = %d, ", has_tbar,
957 										 myframe_has_parts (frame, FRAME_TOP_MASK));
958 		check_side_canvas (asw, od->tbar_side, has_tbar
959 											 || myframe_has_parts (frame, FRAME_TOP_MASK));
960 	}
961 	if (!ASWIN_HFLAGS (asw, AS_Handles)) {
962 		check_side_canvas (asw, od->sbar_side, False);
963 		check_side_canvas (asw, od->left_side, False);
964 		check_side_canvas (asw, od->right_side, False);
965 	} else if (frame != old_frame
966 						 || (old_hints
967 								 && get_flags (old_hints->flags,
968 															 AS_Handles) != ASWIN_HFLAGS (asw,
969 																														AS_Handles))) {
970 		check_side_canvas (asw, od->sbar_side,
971 											 myframe_has_parts (frame, FRAME_BTM_MASK));
972 		check_side_canvas (asw, od->left_side,
973 											 myframe_has_parts (frame, FRAME_LEFT_MASK));
974 		check_side_canvas (asw, od->right_side,
975 											 myframe_has_parts (frame, FRAME_RIGHT_MASK));
976 	}
977 
978 	if (ASWIN_HFLAGS (asw, AS_Handles)
979 			&& get_flags (frame->flags, MYFRAME_NOBORDER)) {
980 		XSetWindowBorderWidth (dpy, asw->frame, 0);
981 		asw->status->frame_border_width = 0;
982 	} else if (asw->hints && get_flags (asw->hints->flags, AS_Border)) {
983 		XSetWindowBorderWidth (dpy, asw->frame, asw->hints->border_width);
984 		asw->status->frame_border_width = asw->hints->border_width;
985 	}
986 
987 	/* make sure all our decoration windows are mapped and in proper order: */
988 	if (!ASWIN_GET_FLAGS (asw, AS_Dead))
989 		XRaiseWindow (dpy, asw->w);
990 
991 	/* 6) now we have to create bar for icon - if it is not client's animated icon */
992 	if (asw->icon_canvas) {
993 		if (old_hints) {
994 			icon_image_changed =
995 					(get_flags
996 					 (asw->hints->client_icon_flags,
997 						AS_ClientIcon | AS_ClientIconPixmap) !=
998 					 get_flags (old_hints->client_icon_flags,
999 											AS_ClientIcon | AS_ClientIconPixmap));
1000 			if (!icon_image_changed)
1001 				icon_image_changed =
1002 						(asw->hints->icon.pixmap != old_hints->icon.pixmap);
1003 			if (!icon_image_changed)
1004 				icon_image_changed =
1005 						(mystrcmp (asw->hints->icon_file, old_hints->icon_file) != 0);
1006 		}
1007 
1008 		if (icon_image_changed) {
1009 			ASImage *icon_image =	get_client_icon_image (ASDefaultScr, asw->hints, 128);
1010 			check_tbar (&(asw->icon_button), (asw->icon_canvas != NULL), AS_ICON_MYSTYLE, icon_image, Scr.Look.ButtonWidth, Scr.Look.ButtonHeight,	/* scaling icon image */
1011 									0, Scr.Look.ButtonAlign,
1012 									Scr.Look.ButtonBevel, Scr.Look.ButtonBevel,
1013 									TEXTURE_TRANSPIXMAP_ALPHA, TEXTURE_TRANSPIXMAP_ALPHA,
1014 									C_IconButton, False);
1015 
1016 			if (icon_image)
1017 				safe_asimage_destroy (icon_image);
1018 		}
1019 	}
1020 	if (asw->icon_button && old_hints == NULL) {
1021 		set_astbar_style (asw->icon_button, BAR_STATE_UNFOCUSED,
1022 											AS_ICON_MYSTYLE);
1023 		set_astbar_style (asw->icon_button, BAR_STATE_FOCUSED,
1024 											AS_ICON_MYSTYLE);
1025 		asw->icon_button->h_border = asw->icon_button->v_border =
1026 				Scr.Look.ButtonIconSpacing;
1027 	}
1028 
1029 	/* 7) now we have to create bar for icon title (optional) */
1030 	check_tbar (&(asw->icon_title),
1031 							get_flags (Scr.Feel.flags, IconTitle)
1032 							&&
1033 							((asw->icon_canvas != NULL
1034 								&& !get_flags (Scr.Look.flags, SeparateButtonTitle))
1035 							 || asw->icon_title_canvas != NULL), AS_ICON_TITLE_MYSTYLE,
1036 							NULL, 0, 0, 0, ALIGN_CENTER, DEFAULT_TBAR_HILITE,
1037 							DEFAULT_TBAR_HILITE, TEXTURE_TRANSPIXMAP_ALPHA,
1038 							TEXTURE_TRANSPIXMAP_ALPHA, C_IconTitle, False);
1039 
1040 	if (asw->icon_title) {
1041 		LOCAL_DEBUG_OUT ("setting icon label to %s", ASWIN_ICON_NAME (asw));
1042 		add_astbar_label (asw->icon_title, 0, 0, 0, frame->title_align,
1043 											DEFAULT_TBAR_HSPACING, DEFAULT_TBAR_VSPACING,
1044 											ASWIN_ICON_NAME (asw), ASWIN_ICON_NAME_ENC (asw));
1045 		set_astbar_style (asw->icon_title, BAR_STATE_FOCUSED,
1046 											AS_ICON_TITLE_MYSTYLE);
1047 		set_astbar_style (asw->icon_title, BAR_STATE_UNFOCUSED,
1048 											AS_ICON_TITLE_UNFOCUS_MYSTYLE);
1049 	}
1050 
1051 	if (asw->hints->mystyle_names[BACK_FOCUSED])
1052 		mystyle_name = asw->hints->mystyle_names[BACK_FOCUSED];
1053 	if (frame->title_style_names[BACK_FOCUSED])
1054 		mystyle_name = frame->title_style_names[BACK_FOCUSED];
1055 	frame_mystyle_name = frame->frame_style_names[BACK_FOCUSED];
1056 
1057 	/* 8) now we have to create actuall bars - for each frame element plus one for the titlebar */
1058 	for (i = 0; i < FRAME_SIDES; ++i)
1059 		clear_flags (asw->internal_flags,
1060 								 ASWF_FirstCornerFollowsTbarSize << i);
1061 	if (old_hints == NULL
1062 			|| (get_flags (old_hints->flags, AS_Handles) !=
1063 					ASWIN_HFLAGS (asw, AS_Handles)) || old_frame != frame) {
1064 		status_changed = True;
1065 		if (ASWIN_HFLAGS (asw, AS_Handles)) {
1066 			for (i = 0; i < FRAME_PARTS; ++i) {
1067 				ASImage *img = NULL;
1068 				unsigned int real_part = od->frame_rotation[i];
1069 				int part_width = frame->part_width[i];
1070 				int part_length = frame->part_length[i];
1071 
1072 				img = frame->parts[i] ? frame->parts[i]->image : NULL;
1073 
1074 				if (img == NULL) {
1075 					if (i < FRAME_SIDES) {
1076 						if (part_width == 0)
1077 							part_width = BOUNDARY_WIDTH;
1078 						if (part_length == 0)
1079 							part_length = 1;
1080 
1081 					} else {
1082 						if (part_width == 0) {
1083 							part_width = CORNER_WIDTH;
1084 							set_flags (asw->internal_flags,
1085 												 ASWF_FirstCornerFollowsTbarSize << (i -
1086 																														 FRAME_SIDES));
1087 						}
1088 						if (part_length == 0)
1089 							part_length = BOUNDARY_WIDTH;
1090 					}
1091 				}
1092 
1093 				if ((0x01 << i) & MYFRAME_HOR_MASK) {
1094 					*(od->in_width) = part_length;
1095 					*(od->in_height) = part_width;
1096 				} else {
1097 					*(od->in_width) = part_width;
1098 					*(od->in_height) = part_length;
1099 				}
1100 				LOCAL_DEBUG_OUT
1101 						("part(%d)->real_part(%d)->from_size(%ux%u)->in_size(%ux%u)->out_size(%ux%u)",
1102 						 i, real_part, frame->part_width[i], frame->part_length[i],
1103 						 *(od->in_width), *(od->in_height), *(od->out_width),
1104 						 *(od->out_height));
1105 				check_tbar (&(asw->frame_bars[real_part]), IsFramePart (frame, i),
1106 										frame_mystyle_name ? frame_mystyle_name : mystyle_name,
1107 										img, *(od->out_width), *(od->out_height), od->flip,
1108 										frame->part_align[i], frame->part_fbevel[i],
1109 										frame->part_ubevel[i], TEXTURE_TRANSPIXMAP_ALPHA,
1110 										TEXTURE_TRANSPIXMAP_ALPHA, frame_contexts[i],
1111 										(i < FRAME_SIDES) ? &(frame->part_slicing[i]) : NULL);
1112 			}
1113 		} else
1114 			for (i = 0; i < FRAME_PARTS; ++i)
1115 				check_tbar (&(asw->frame_bars[i]), False, NULL, NULL, 0, 0, 0, 0,
1116 										0, 0, 0, 0, C_NO_CONTEXT, NULL);
1117 
1118 		check_tbar (&(asw->tbar), has_tbar, mystyle_name, NULL, 0, 0,
1119 								od->flip,
1120 								frame->title_align,
1121 								frame->title_fbevel, frame->title_ubevel,
1122 								frame->title_fcm, frame->title_ucm, C_TITLE, NULL);
1123 		if (asw->tbar) {
1124 			int fhue = -1, fsat = -1, uhue = -1, usat = -1;
1125 			if (get_flags (frame->set_title_attr, MYFRAME_TitleFHueSet))
1126 				fhue = frame->title_fhue;
1127 			if (get_flags (frame->set_title_attr, MYFRAME_TitleFSatSet))
1128 				fsat = frame->title_fsat;
1129 			if (get_flags (frame->set_title_attr, MYFRAME_TitleUHueSet))
1130 				uhue = frame->title_fhue;
1131 			if (get_flags (frame->set_title_attr, MYFRAME_TitleUSatSet))
1132 				usat = frame->title_fsat;
1133 
1134 			set_astbar_huesat (asw->tbar, BAR_STATE_FOCUSED, fhue, fsat);
1135 			set_astbar_huesat (asw->tbar, BAR_STATE_UNFOCUSED, uhue, usat);
1136 		}
1137 
1138 		tbar_created = (asw->tbar != NULL);
1139 	}
1140 
1141 	if (asw->tbar) {							/* 9) now we have to setup titlebar buttons */
1142 		ASFlagType title_align = frame->title_align;
1143 		ASFlagType btn_mask = compile_titlebuttons_mask (asw->hints);
1144 #ifdef SHAPE
1145 		if (get_flags (frame->condense_titlebar, ALIGN_LEFT | ALIGN_RIGHT))
1146 			ASWIN_SET_FLAGS (asw, AS_ShapedDecor);
1147 #endif
1148 
1149 		if (old_hints == NULL ||
1150 				get_flags (old_hints->flags,
1151 									 AS_VerticalTitle) != ASWIN_HFLAGS (asw,
1152 																											AS_VerticalTitle)) {
1153 			set_astbar_flip (asw->tbar,
1154 											 ASWIN_HFLAGS (asw,
1155 																		 AS_VerticalTitle) ? FLIP_VERTICAL :
1156 											 0);
1157 			if (!tbar_created) {
1158 				tbar_created = True;
1159 				delete_astbar_tile (asw->tbar, -1);
1160 			}
1161 		}
1162 		/* need to add some titlebuttons */
1163 		/* Don't need to do this as we already have padding set for label
1164 		 * if( tbar_created )
1165 		 *  {
1166 		 *        asw->tbar->h_spacing = DEFAULT_TBAR_SPACING ;
1167 		 *        asw->tbar->v_spacing = DEFAULT_TBAR_SPACING ;
1168 		 *  }
1169 		 */
1170 
1171 		if (!tbar_created && old_hints != NULL) {
1172 			ASFlagType old_btn_mask = compile_titlebuttons_mask (old_hints);
1173 			if (old_btn_mask != btn_mask)
1174 				tbar_created = True;
1175 			else if (frame != old_frame)
1176 				tbar_created = True;
1177 			if (tbar_created)
1178 				delete_astbar_tile (asw->tbar, -1);
1179 		}
1180 
1181 		if (!tbar_created) {
1182 			if (old_hints == NULL ||
1183 					mystrcmp (asw->hints->names[0], old_hints->names[0]) != 0) {
1184 				ASCanvas *canvas =
1185 						ASWIN_HFLAGS (asw,
1186 													AS_VerticalTitle) ? asw->
1187 						frame_sides[FR_W] : asw->frame_sides[FR_N];
1188 				/* label ( goes on top of above pixmap ) */
1189 				if (change_astbar_first_label
1190 						(asw->tbar, ASWIN_NAME (asw), ASWIN_NAME_ENCODING (asw)))
1191 					if (canvas) {
1192 						render_astbar (asw->tbar, canvas);
1193 						invalidate_canvas_save (canvas);
1194 						update_canvas_display (canvas);
1195 					}
1196 			}
1197 		} else {
1198 			Bool rtitle_spacer_added = False;
1199 			Bool ltitle_spacer_added = False;
1200 			unsigned int tbar_layout_row[MYFRAME_TITLE_BACKS];
1201 			unsigned int tbar_layout_col[MYFRAME_TITLE_BACKS];
1202 
1203 			compile_tbar_layout (tbar_layout_row, od->default_tbar_elem_row,
1204 													 frame->left_layout, frame->right_layout);
1205 			compile_tbar_layout (tbar_layout_col, od->default_tbar_elem_col,
1206 													 frame->left_layout, frame->right_layout);
1207 
1208 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPU)
1209 			for (i = 0; i < MYFRAME_TITLE_BACKS; ++i) {
1210 				LOCAL_DEBUG_OUT ("TitlebarLayout col[%d] = %d", i,
1211 												 tbar_layout_col[i]);
1212 				LOCAL_DEBUG_OUT ("TitlebarLayout row[%d] = %d", i,
1213 												 tbar_layout_row[i]);
1214 			}
1215 #endif
1216 
1217 			for (i = MYFRAME_TITLE_BACK_LBTN; i < MYFRAME_TITLE_BACKS; ++i)
1218 				if (frame->title_backs[i] && frame->title_backs[i]->image) {
1219 					LOCAL_DEBUG_OUT ("Adding Title Back #%d", i);
1220 					if (frame->title_backs_slicing[i].flags != 0) {
1221 						ASImage *im = frame->title_backs[i]->image;
1222 						int xs = 0, xe = 0, ys = im->width, ye = im->height;
1223 						geometry2slicing (frame->title_backs_slicing[i], &xs, &xe, &ys,
1224 															&ye);
1225 						add_astbar_image (asw->tbar,
1226 															tbar_layout_col[ASO_TBAR_ELEM_LBTN + i],
1227 															tbar_layout_row[ASO_TBAR_ELEM_LBTN + i],
1228 															od->flip,
1229 															fix_background_align (frame->
1230 																										title_backs_align[i]),
1231 															im, xs, xe, ys, ye);
1232 					} else
1233 						add_astbar_icon (asw->tbar,
1234 														 tbar_layout_col[ASO_TBAR_ELEM_LBTN + i],
1235 														 tbar_layout_row[ASO_TBAR_ELEM_LBTN + i],
1236 														 od->flip,
1237 														 fix_background_align (frame->
1238 																									 title_backs_align[i]),
1239 														 frame->title_backs[i]->image);
1240 					if (i == MYFRAME_TITLE_BACK_RTITLE_SPACER)
1241 						rtitle_spacer_added = True;
1242 					else if (i == MYFRAME_TITLE_BACK_LTITLE_SPACER)
1243 						ltitle_spacer_added = True;
1244 
1245 				}
1246 #if 1
1247 			/* special handling to accomodate FIT_LABEL_SIZE alignment of the title */
1248 			if (frame->title_backs[MYFRAME_TITLE_BACK_LBL] &&
1249 					frame->title_backs[MYFRAME_TITLE_BACK_LBL]->image) {
1250 				LOCAL_DEBUG_OUT ("title_back_align = 0x%lX",
1251 												 frame->title_backs_align[MYFRAME_TITLE_BACK_LBL]);
1252 				if (get_flags
1253 						(frame->title_backs_align[MYFRAME_TITLE_BACK_LBL],
1254 						 FIT_LABEL_SIZE)) {
1255 					/* left spacer  - if we have an icon to go under the label if align is right or center */
1256 					if (get_flags (frame->title_align, ALIGN_RIGHT)
1257 							&& !ltitle_spacer_added)
1258 						add_astbar_spacer (asw->tbar,
1259 															 tbar_layout_col
1260 															 [ASO_TBAR_ELEM_LTITLE_SPACER],
1261 															 tbar_layout_row
1262 															 [ASO_TBAR_ELEM_LTITLE_SPACER], od->flip,
1263 															 PAD_LEFT, 1, 1);
1264 
1265 					/* right spacer - if we have an icon to go under the label and align is left or center */
1266 					if (get_flags (frame->title_align, ALIGN_LEFT)
1267 							&& !rtitle_spacer_added)
1268 						add_astbar_spacer (asw->tbar,
1269 															 tbar_layout_col
1270 															 [ASO_TBAR_ELEM_RTITLE_SPACER],
1271 															 tbar_layout_row
1272 															 [ASO_TBAR_ELEM_RTITLE_SPACER], od->flip,
1273 															 PAD_RIGHT, 1, 1);
1274 					title_align = 0;
1275 				}
1276 			}
1277 #endif
1278 
1279 			/* label ( goes on top of above pixmap ) */
1280 			add_astbar_label (asw->tbar,
1281 												tbar_layout_col[ASO_TBAR_ELEM_LBL],
1282 												tbar_layout_row[ASO_TBAR_ELEM_LBL],
1283 												od->flip,
1284 												title_align, frame->title_h_spacing,
1285 												frame->title_v_spacing, ASWIN_NAME (asw),
1286 												ASWIN_NAME_ENCODING (asw));
1287 
1288 			/* all the buttons go after the label to be rendered over it */
1289 			/* left buttons : */
1290 			add_astbar_btnblock (asw->tbar,
1291 													 tbar_layout_col[ASO_TBAR_ELEM_LBTN],
1292 													 tbar_layout_row[ASO_TBAR_ELEM_LBTN],
1293 													 od->flip, frame->left_btn_align,
1294 													 &(Scr.Look.ordered_buttons[0]), btn_mask,
1295 													 Scr.Look.button_first_right,
1296 													 Scr.Look.TitleButtonXOffset[0],
1297 													 Scr.Look.TitleButtonYOffset[0],
1298 													 Scr.Look.TitleButtonSpacing[0],
1299 													 od->left_btn_order);
1300 
1301 			/* right buttons : */
1302 			add_astbar_btnblock (asw->tbar,
1303 													 tbar_layout_col[ASO_TBAR_ELEM_RBTN],
1304 													 tbar_layout_row[ASO_TBAR_ELEM_RBTN],
1305 													 od->flip, frame->right_btn_align,
1306 													 &(Scr.Look.
1307 														 ordered_buttons[Scr.Look.button_first_right]),
1308 													 btn_mask,
1309 													 TITLE_BUTTONS - Scr.Look.button_first_right,
1310 													 Scr.Look.TitleButtonXOffset[1],
1311 													 Scr.Look.TitleButtonYOffset[1],
1312 													 Scr.Look.TitleButtonSpacing[1],
1313 													 od->right_btn_order);
1314 			/* titlebar balloons */
1315 			for (i = 0; i < TITLE_BUTTONS; ++i) {
1316 				if (get_flags (btn_mask, C_TButton0 << i)) {
1317 					char *str =
1318 							list_functions_by_context (C_TButton0 << i, asw->hints);
1319 					LOCAL_DEBUG_OUT ("balloon text will be \"%s\"",
1320 													 str ? str : "none");
1321 					set_astbar_balloon2 (asw->tbar, TitlebarBalloons,
1322 															 C_TButton0 << i, str, AS_Text_ASCII);
1323 					if (str)
1324 						free (str);
1325 				}
1326 			}
1327 		}
1328 	}
1329 
1330 	if (ASWIN_HFLAGS (asw, AS_WindowOpacity)) {
1331 		set_32bit_property (asw->frame, _XA_NET_WM_WINDOW_OPACITY, XA_CARDINAL,
1332 												asw->hints->window_opacity);
1333 	}
1334 
1335 
1336 	/* we also need to setup label, unfocused/sticky style and tbar sizes -
1337 	 * it all is done when we change windows state, or move/resize it */
1338 	/*since we might have destroyed/created some windows - we have to refresh grabs : */
1339 	grab_window_input (asw, False);
1340 	if (get_flags (asw->internal_flags, ASWF_WindowComplete)) {
1341 		/* we need to map all the possibly created subwindows if window is not iconic */
1342 		if (!ASWIN_GET_FLAGS (asw, AS_Iconic)) {
1343 			for (i = 0; i < FRAME_SIDES; ++i)
1344 				map_canvas_window (asw->frame_sides[i], False);
1345 
1346 /*			LOCAL_DEBUG_OUT("mapping frame subwindows for client %lX, frame canvas = %p", asw->w, asw->frame_canvas );
1347 			XMapSubwindows(dpy, asw->frame); */
1348 		} else {
1349 			map_canvas_window (asw->icon_canvas, False);
1350 			map_canvas_window (asw->icon_title_canvas, False);
1351 		}
1352 	}
1353 
1354 	return status_changed;
1355 }
1356 
1357 
1358 /*************************************************************************/
1359 /*   Main window decoration routine                                      */
1360 /*************************************************************************/
redecorate_window(ASWindow * asw,Bool free_resources)1361 void redecorate_window (ASWindow * asw, Bool free_resources)
1362 {
1363 	int i;
1364 
1365 	LOCAL_DEBUG_OUT ("as?w(%p)->free_res(%d)", asw, free_resources);
1366 	if (AS_ASSERT (asw))
1367 		return;
1368 
1369 	if (free_resources || asw->hints == NULL || asw->status == NULL) {	/* destroy window decorations here : */
1370 		/* destruction goes in reverese order ! */
1371 		check_tbar (&(asw->icon_title), False, NULL, NULL, 0, 0, 0, 0, 0, 0, 0,
1372 								0, C_NO_CONTEXT, NULL);
1373 		check_tbar (&(asw->icon_button), False, NULL, NULL, 0, 0, 0, 0, 0, 0,
1374 								0, 0, C_NO_CONTEXT, NULL);
1375 		check_tbar (&(asw->tbar), False, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0,
1376 								C_NO_CONTEXT, NULL);
1377 		i = FRAME_PARTS;
1378 		while (--i >= 0)
1379 			check_tbar (&(asw->frame_bars[i]), False, NULL, NULL, 0, 0, 0, 0, 0,
1380 									0, 0, 0, C_NO_CONTEXT, NULL);
1381 
1382 		check_side_canvas (asw, FR_W, False);
1383 		check_side_canvas (asw, FR_E, False);
1384 		check_side_canvas (asw, FR_S, False);
1385 		check_side_canvas (asw, FR_N, False);
1386 
1387 		if (asw->icon_canvas == asw->icon_title_canvas)
1388 			asw->icon_title_canvas = NULL;
1389 		if (asw->icon_title_canvas && asw->icon_title_canvas->w)
1390 			check_icon_title_canvas (asw, False, False);
1391 		if (asw->icon_canvas && asw->icon_canvas->w)
1392 			check_icon_canvas (asw, False);
1393 		check_client_canvas (asw, False);
1394 		check_frame_canvas (asw, False);
1395 
1396 		return;
1397 	}
1398 
1399 	/* 1) we need to create our frame window : */
1400 	if (check_frame_canvas (asw, True) == NULL)
1401 		return;
1402 
1403 	/* 2) we need to reparent our title window : */
1404 	if (check_client_canvas (asw, True) == NULL)
1405 		return;
1406 
1407 	hints2decorations (asw, NULL);
1408 
1409 }
1410 
1411 /****************************************************************************
1412  *
1413  * Sets up the shaped window borders
1414  *
1415  ****************************************************************************/
SetShape(ASWindow * asw,int w)1416 void SetShape (ASWindow * asw, int w)
1417 {
1418 #ifdef SHAPE
1419 	LOCAL_DEBUG_CALLER_OUT ("asw(%p)->client(%lX)", asw, asw ? asw->w : 0);
1420 
1421 	if (asw) {
1422 
1423 		if (ASWIN_GET_FLAGS (asw, AS_Dead)) {
1424 			clear_canvas_shape (asw->frame_canvas, True);
1425 			return;
1426 		}
1427 
1428 		if (ASWIN_GET_FLAGS (asw, AS_Iconic)) {	/* todo: update icon's shape */
1429 
1430 		} else {
1431 			int i, tbar_side = -1;
1432 			int child_x = 0;
1433 			int child_y = 0;
1434 			unsigned int width, height, bw;
1435 			XRectangle rect;
1436 
1437 			/* starting with an empty list of rectangles */
1438 			if (asw->frame_canvas->shape)
1439 				flush_vector (asw->frame_canvas->shape);
1440 			else
1441 				asw->frame_canvas->shape = create_shape ();
1442 
1443 			get_current_canvas_geometry (asw->client_canvas, &child_x, &child_y,
1444 																	 &width, &height, &bw);
1445 			rect.x = 0;
1446 			rect.y = 0;
1447 			rect.width = width;
1448 			rect.height = height;
1449 
1450 			/* adding rectangles for all the frame decorations */
1451 			if (asw->shading_steps == 0 && ASWIN_GET_FLAGS (asw, AS_Shaded)) {
1452 				ASOrientation *od = get_orientation_data (asw);
1453 				tbar_side = od->tbar_side;
1454 			}
1455 			for (i = 0; i < FRAME_SIDES; ++i)
1456 				if (asw->frame_sides[i] && (i == tbar_side || tbar_side == -1)) {
1457 					int x, y;
1458 					unsigned int s_width, s_height, bw;
1459 					LOCAL_DEBUG_OUT (" Frame side %d", i);
1460 					get_current_canvas_geometry (asw->frame_sides[i], &x, &y,
1461 																			 &s_width, &s_height, &bw);
1462 
1463 					combine_canvas_shape_at_geom (asw->frame_canvas,
1464 																				asw->frame_sides[i], x, y, s_width,
1465 																				s_height, bw);
1466 /*                  	combine_canvas_shape( asw->frame_canvas, asw->frame_sides[i] ); */
1467 				}
1468 
1469 			/* subtract client rectangle, before adding clients shape */
1470 			subtract_shape_rectangle (asw->frame_canvas->shape, &rect, 1,
1471 																child_x, child_y, asw->frame_canvas->width,
1472 																asw->frame_canvas->height);
1473 			/* add clients shape */
1474 			combine_canvas_shape_at_geom (asw->frame_canvas, asw->client_canvas,
1475 																		child_x, child_y, width, height, bw);
1476 
1477 #ifndef NO_DEBUG_OUTPUT
1478 			print_shape (asw->frame_canvas->shape);
1479 #endif
1480 			/* apply shape */
1481 			update_canvas_display_mask (asw->frame_canvas, True);
1482 			set_flags (asw->internal_flags, ASWF_PendingShapeRemoval);
1483 
1484 		}
1485 	}
1486 #endif													/* SHAPE */
1487 }
1488 
ClearShape(ASWindow * asw)1489 void ClearShape (ASWindow * asw)
1490 {
1491 #ifdef SHAPE
1492 	if (asw && asw->frame_canvas) {
1493 		clear_canvas_shape (asw->frame_canvas, True);
1494 		clear_flags (asw->internal_flags, ASWF_PendingShapeRemoval);
1495 	}
1496 #endif													/* SHAPE */
1497 }
1498