1 /*
2  * pwm/draw.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2001.
5  *
6  * You may distribute and modify this program under the terms of either
7  * the Clarified Artistic License or the GNU GPL, version 2 or later.
8  */
9 
10 #include <X11/Xlib.h>
11 #include <string.h>
12 
13 #include "common.h"
14 #include "screen.h"
15 #include "draw.h"
16 #include "config.h"
17 #include "font.h"
18 #include "clientwin.h"
19 #include "frame.h"
20 #include "menu.h"
21 
22 
draw_bevel(Window win,GC gc,int x,int y,int w,int h,int bw,int hl,int sh)23 static void draw_bevel(Window win, GC gc,
24 					   int x, int y, int w, int h,
25 					   int bw, int hl, int sh)
26 {
27 	XPoint points[3];
28 	int i=0;
29 
30 	w--;
31 	h--;
32 
33 	XSetForeground(wglobal.dpy, gc, hl);
34 
35 	for(i=0; i<bw; i++){
36 		points[0].x=x+i;		points[0].y=y+h-i+1;
37 		points[1].x=x+i;		points[1].y=y+i;
38 		points[2].x=x+w-i;		points[2].y=y+i;
39 
40 		XDrawLines(wglobal.dpy, win, gc, points, 3, CoordModeOrigin);
41 	}
42 
43 
44 	XSetForeground(wglobal.dpy, gc, sh);
45 
46 	for(i=0; i<bw; i++){
47 		points[0].x=x+w-i;		points[0].y=y+i;
48 		points[1].x=x+w-i;		points[1].y=y+h-i;
49 		points[2].x=x+i+1;		points[2].y=y+h-i;
50 
51 		XDrawLines(wglobal.dpy, win, gc, points, 3, CoordModeOrigin);
52 	}
53 }
54 
55 
56 
draw_box(Window win,GC gc,const WColorGroup * colors,int x,int y,int w,int h,bool fill)57 static void draw_box(Window win, GC gc, const WColorGroup *colors,
58 					 int x, int y, int w, int h, bool fill)
59 {
60 	if(fill){
61 		XSetForeground(wglobal.dpy, gc, colors->pixels[WCG_PIX_BG]);
62 		XFillRectangle(wglobal.dpy, win, gc, x, y, w, h);
63 	}
64 
65 	draw_bevel(win, gc, x, y, w, h, CF_BEVEL_WIDTH,
66 			   colors->pixels[WCG_PIX_HL], colors->pixels[WCG_PIX_SH]);
67 }
68 
69 
70 /* */
71 
72 
draw_tab(WGRData * grdata,Window win,const WColorGroup * colors,int x,int y,int w,int h,bool fill,const char * str,int str_w)73 static void draw_tab(WGRData *grdata, Window win,
74 					 const WColorGroup *colors,
75 					 int x, int y, int w, int h,
76 					 bool fill, const char *str, int str_w)
77 {
78 	GC gc=grdata->gc;
79 
80 	draw_box(win, gc, colors, x, y, w, h, fill);
81 
82 	if(str!=NULL){
83 		XSetForeground(wglobal.dpy, gc, colors->pixels[WCG_PIX_FG]);
84 		XDrawString(wglobal.dpy, win, gc, x+w/2-str_w/2,
85 					y+CF_TAB_TEXT_Y_OFF+FONT_BASELINE(grdata->font),
86 					str, strlen(str));
87 	}
88 }
89 
90 
draw_border(WGRData * grdata,Window win,const WColorGroup * colors,int x,int y,int w,int h)91 static void draw_border(WGRData *grdata, Window win,
92 						const WColorGroup *colors,
93 						int x, int y, int w, int h)
94 {
95 
96 	int sw=CF_BEVEL_WIDTH;
97 	int dw=CF_BORDER_WIDTH-CF_BEVEL_WIDTH;
98 	GC gc=grdata->gc;
99 
100 	draw_bevel(win, gc, x, y, w, h, sw,
101 			   colors->pixels[WCG_PIX_HL], colors->pixels[WCG_PIX_SH]);
102 	draw_bevel(win, gc, x+dw, y+dw, w-dw*2, h-dw*2, sw,
103 			   colors->pixels[WCG_PIX_SH], colors->pixels[WCG_PIX_HL]);
104 }
105 
106 
copy_masked(const WGRData * grdata,Drawable src,Drawable dst,int src_x,int src_y,int w,int h,int dst_x,int dst_y)107 static void copy_masked(const WGRData *grdata, Drawable src, Drawable dst,
108 						int src_x, int src_y, int w, int h,
109 						int dst_x, int dst_y)
110 {
111 
112 	XSetClipMask(wglobal.dpy, grdata->copy_gc, src);
113 	XSetClipOrigin(wglobal.dpy, grdata->copy_gc, dst_x, dst_y);
114 	XCopyPlane(wglobal.dpy, src, dst, grdata->copy_gc, src_x, src_y,
115 			   w, h, dst_x, dst_y, 1);
116 }
117 
118 
119 /* */
120 
121 
draw_xor_frame(int x,int y,int w,int h,int bar_h,int bar_w)122 static void draw_xor_frame(int x, int y, int w, int h, int bar_h, int bar_w)
123 {
124 	XPoint fpts[5];
125 	XPoint bpts[4];
126 	WGRData *grdata=GRDATA;
127 
128 	if(bar_w>w*CF_BAR_MAX_WIDTH_Q)
129 		bar_w=w*CF_BAR_MAX_WIDTH_Q;
130 
131 	if(bar_h!=0){
132 		bpts[0].x=x;
133 		bpts[0].y=y+bar_h;
134 		bpts[1].x=x;
135 		bpts[1].y=y;
136 		bpts[2].x=x+bar_w;
137 		bpts[2].y=y;
138 		bpts[3].x=x+bar_w;
139 		bpts[3].y=y+bar_h;
140 		XDrawLines(wglobal.dpy, SCREEN->root, grdata->xor_gc, bpts, 4,
141 				   CoordModeOrigin);
142 	}
143 
144 	fpts[0].x=x;
145 	fpts[0].y=y+bar_h;
146 	fpts[1].x=x+w;
147 	fpts[1].y=y+bar_h;
148 	fpts[2].x=x+w;
149 	fpts[2].y=y+h;
150 	fpts[3].x=x;
151 	fpts[3].y=y+h;
152 	fpts[4].x=x;
153 	fpts[4].y=y+bar_h;
154 
155 	XDrawLines(wglobal.dpy, SCREEN->root, grdata->xor_gc, fpts, 5,
156 			   CoordModeOrigin);
157 }
158 
159 
draw_rubberband(const WWinObj * obj,int x,int y,int w,int h)160 void draw_rubberband(const WWinObj *obj, int x, int y, int w, int h)
161 {
162 	WFrame *frame;
163 
164 	if(!WTHING_IS(obj, WTHING_FRAME)){
165 		draw_xor_frame(x, y, w, h, 0, 0);
166 	}else{
167 		frame=(WFrame*)obj;
168 		draw_xor_frame(x, y, w, h, /*w+frame->frame_ix*2, h+frame->frame_iy*2,*/
169 					   frame->bar_h, frame->bar_w);
170 	}
171 }
172 
173 
draw_moveres(const char * str)174 void draw_moveres(const char *str)
175 {
176 	WGRData *grdata=GRDATA;
177 	WScreen *scr=SCREEN;
178 	int w=XTextWidth(grdata->font, str, strlen(str));
179 
180 /*	XClearWindow(wglobal.dpy, scr->moveres_win);*/
181 
182 	XClearArea(wglobal.dpy, scr->moveres_win,
183 			   CF_BEVEL_WIDTH, CF_BEVEL_WIDTH,
184 			   scr->moveres_win_w-CF_BEVEL_WIDTH*2,
185 			   scr->moveres_win_h-CF_BEVEL_WIDTH*2, False);
186 
187 	draw_tab(GRDATA, scr->moveres_win, &(grdata->tab_sel_colors),
188 			 0, 0, scr->moveres_win_w, scr->moveres_win_h,
189 			 FALSE, str, w);
190 }
191 
192 
draw_tabdrag(const WClientWin * cwin)193 void draw_tabdrag(const WClientWin *cwin)
194 {
195 	WFrame *frame;
196 	const WColorGroup *tabcolor;
197 	WGRData *grdata=GRDATA;
198 	Window win=SCREEN->tabdrag_win;
199 
200 	frame=CWIN_FRAME(cwin);
201 
202 	if((WWinObj*)frame==wglobal.current_winobj){
203 		if(cwin==frame->current_cwin)
204 			tabcolor=&(grdata->act_tab_sel_colors);
205 		else
206 			tabcolor=&(grdata->act_tab_colors);
207 	}else{
208 		if(cwin==frame->current_cwin)
209 			tabcolor=&(grdata->tab_sel_colors);
210 		else
211 			tabcolor=&(grdata->tab_colors);
212 	}
213 
214 	XSetWindowBackground(wglobal.dpy, win, tabcolor->pixels[WCG_PIX_BG]);
215 	XClearWindow(wglobal.dpy, win);
216 
217 	draw_tab(grdata, win, tabcolor, 0, 0, frame->tab_w, frame->bar_h, FALSE,
218 			 cwin->label, cwin->label_width);
219 }
220 
221 
222 
223 
224 /* */
225 
226 
draw_frame_frame(const WFrame * frame,bool complete)227 void draw_frame_frame(const WFrame *frame, bool complete)
228 {
229 	WGRData *grdata=GRDATA;
230 	WColorGroup *colors;
231 #ifdef CF_WANT_TRANSPARENT_TERMS
232 	int fw, off, w, h;
233 #endif
234 
235 	if((WWinObj*)frame==wglobal.current_winobj)
236 		colors=&(grdata->act_base_colors);
237 	else
238 		colors=&(grdata->base_colors);
239 
240 #ifndef CF_WANT_TRANSPARENT_TERMS
241 	if(complete){
242 		XSetWindowBackground(wglobal.dpy, frame->frame_win,
243 							 colors->pixels[WCG_PIX_BG]);
244 		XClearWindow(wglobal.dpy, frame->frame_win);
245 	}
246 #else
247 	off=CF_BEVEL_WIDTH;
248 	fw=CF_BORDER_WIDTH-CF_BEVEL_WIDTH*2;
249 	w=FRAME_W(frame)-CF_BEVEL_WIDTH*2;
250 	h=FRAME_H(frame)-CF_BEVEL_WIDTH*2;
251 
252 	XSetForeground(wglobal.dpy, grdata->gc, colors->pixels[WCG_PIX_BG]);
253 
254 	/* top */
255 	XFillRectangle(wglobal.dpy, frame->frame_win, grdata->gc,
256 				   off, off, w, fw);
257 	/* bottom */
258 	XFillRectangle(wglobal.dpy, frame->frame_win, grdata->gc,
259 				   off, off+h-fw, w, fw);
260 	/* left */
261 	XFillRectangle(wglobal.dpy, frame->frame_win, grdata->gc,
262 				   off, off+fw, fw, h-fw*2);
263 	/* right */
264 	XFillRectangle(wglobal.dpy, frame->frame_win, grdata->gc,
265 				   off+w-fw, off+fw, fw, h-fw*2);
266 
267 	/* center */
268 	XFillRectangle(wglobal.dpy, frame->frame_win, grdata->gc,
269 				   CF_BORDER_WIDTH, CF_BORDER_WIDTH,
270 				   FRAME_W(frame)-CF_BORDER_WIDTH*2,
271 				   FRAME_H(frame)-CF_BORDER_WIDTH*2);
272 #endif
273 	draw_border(grdata, frame->frame_win, colors, 0, 0,
274 				FRAME_W(frame), FRAME_H(frame));
275 }
276 
277 
draw_frame_bar(const WFrame * frame,bool complete)278 void draw_frame_bar(const WFrame *frame, bool complete)
279 {
280 	WColorGroup *selcolor, *tabcolor, *colors;
281 	WClientWin *cwin;
282 	WGRData *grdata=GRDATA;
283 	int x=0;
284 
285 	if(WFRAME_IS_NO_BAR(frame))
286 		return;
287 
288 	if((WWinObj*)frame==wglobal.current_winobj){
289 		selcolor=&(grdata->act_tab_sel_colors);
290 		colors=tabcolor=&(grdata->act_tab_colors);
291 	}else{
292 		selcolor=&(grdata->tab_sel_colors);
293 		colors=tabcolor=&(grdata->tab_colors);
294 	}
295 
296 	if(complete){
297 		XSetWindowBackground(wglobal.dpy, frame->bar_win,
298 							 tabcolor->pixels[WCG_PIX_BG]);
299 		XClearWindow(wglobal.dpy, frame->bar_win);
300 	}
301 
302 	for(cwin=first_clientwin((WThing*)frame);
303 		cwin!=NULL;
304 		cwin=next_clientwin(cwin)){
305 
306 		if(cwin==frame->current_cwin)
307 			colors=selcolor;
308 		else
309 			colors=tabcolor;
310 
311 		draw_tab(grdata, frame->bar_win, colors,
312 				 x, 0, frame->tab_w, frame->bar_h, TRUE,
313 				 cwin->label, cwin->label_width);
314 
315 		if(cwin->flags&CWIN_TAGGED){
316 			XSetForeground(wglobal.dpy, grdata->gc,
317 						   colors->pixels[WCG_PIX_FG]);
318 
319 			XDrawRectangle(wglobal.dpy, frame->bar_win, grdata->gc,
320 						   x+CF_BEVEL_WIDTH, CF_BEVEL_WIDTH,
321 						   frame->tab_w-1-2*CF_BEVEL_WIDTH,
322 						   frame->bar_h-1-2*CF_BEVEL_WIDTH);
323 			XDrawRectangle(wglobal.dpy, frame->bar_win, grdata->gc,
324 						   x+CF_BEVEL_WIDTH+1, CF_BEVEL_WIDTH+1,
325 						   frame->tab_w-3-2*CF_BEVEL_WIDTH,
326 						   frame->bar_h-3-2*CF_BEVEL_WIDTH);
327 		}
328 
329 		if(cwin->flags&CWIN_DRAG){
330 			XFillRectangle(wglobal.dpy, frame->bar_win, grdata->stipple_gc,
331 						   x, 0, frame->tab_w, frame->bar_h);
332 		}
333 
334 		x+=frame->tab_w;
335 	}
336 
337 	if(WWINOBJ_IS_STICKY(frame)){
338 		XSetForeground(wglobal.dpy, grdata->copy_gc,
339 					   colors->pixels[WCG_PIX_FG]);
340 		copy_masked(grdata, grdata->stick_pixmap, frame->bar_win,
341 					0, 0, grdata->stick_pixmap_w, grdata->stick_pixmap_h,
342 					frame->bar_w-grdata->stick_pixmap_w-CF_BEVEL_WIDTH,
343 					CF_BEVEL_WIDTH);
344 	}
345 }
346 
347 
348 /* */
349 
350 
menu_entry_y(const WMenu * menu,int entry)351 static int menu_entry_y(const WMenu *menu, int entry)
352 {
353 	int y=CF_MENU_V_SPACE;
354 
355 	y+=menu->title_height;
356 	y+=entry*menu->entry_height;
357 
358 	return y;
359 }
360 
361 
draw_menu_entrytext(const WMenu * menu,const WGRData * grdata,int y,const WMenuEnt * ent)362 static void draw_menu_entrytext(const WMenu *menu, const WGRData *grdata,
363 								int y, const WMenuEnt *ent)
364 {
365 	XDrawString(wglobal.dpy, menu->menu_win, grdata->menu_gc,
366 				CF_MENUENT_H_SPACE,
367 				y+CF_MENUENT_V_SPACE+FONT_BASELINE(grdata->menu_font),
368 				ent->name, strlen(ent->name));
369 
370 	if(ent->flags&WMENUENT_SUBMENU)
371 		XDrawString(wglobal.dpy, menu->menu_win, grdata->menu_gc,
372 					menu->w-grdata->submenu_ind_w-CF_MENUENT_H_SPACE,
373 					y+CF_MENUENT_V_SPACE+FONT_BASELINE(grdata->menu_font),
374 					"->", 2);
375 }
376 
377 
do_draw_menu_selection(const WMenu * menu,int y,const WColorGroup * colors)378 static void do_draw_menu_selection(const WMenu *menu, int y,
379 								   const WColorGroup *colors)
380 {
381 	draw_box(menu->menu_win, GRDATA->gc, colors, CF_BEVEL_WIDTH, y,
382 			 menu->w-2*CF_BEVEL_WIDTH, menu->entry_height, TRUE);
383 	XSetForeground(wglobal.dpy, GRDATA->menu_gc, colors->pixels[WCG_PIX_FG]);
384 	draw_menu_entrytext(menu, GRDATA, y,
385 						&(menu->data->entries[menu->selected]));
386 }
387 
388 
do_erase_menu_selection(const WMenu * menu,int y,const WColorGroup * colors)389 static void do_erase_menu_selection(const WMenu *menu, int y,
390 									const WColorGroup *colors)
391 {
392 	WGRData *grdata=GRDATA;
393 
394 	XSetForeground(wglobal.dpy, grdata->gc, colors->pixels[WCG_PIX_BG]);
395 	XFillRectangle(wglobal.dpy, menu->menu_win, grdata->gc,
396 				   CF_BEVEL_WIDTH, y,
397 				   menu->w-2*CF_BEVEL_WIDTH,
398 				   menu->entry_height);
399 	XSetForeground(wglobal.dpy, GRDATA->menu_gc, colors->pixels[WCG_PIX_FG]);
400 	draw_menu_entrytext(menu, GRDATA, y,
401 						&(menu->data->entries[menu->selected]));
402 }
403 
404 
draw_menu_selection(const WMenu * menu)405 void draw_menu_selection(const WMenu *menu)
406 {
407 	WColorGroup *colors;
408 
409 	if(menu->selected<0)
410 		return;
411 
412 	colors=((WWinObj*)menu==wglobal.current_winobj ?
413 			&(GRDATA->act_sel_colors) :
414 			&(GRDATA->sel_colors));
415 
416 	do_draw_menu_selection(menu, menu_entry_y(menu, menu->selected), colors);
417 }
418 
419 
erase_menu_selection(const WMenu * menu)420 void erase_menu_selection(const WMenu *menu)
421 {
422 	WColorGroup *colors;
423 
424 	if(menu->selected<0)
425 		return;
426 
427 	colors=((WWinObj*)menu==wglobal.current_winobj ?
428 			&(GRDATA->act_base_colors) :
429 			&(GRDATA->base_colors));
430 
431 	do_erase_menu_selection(menu, menu_entry_y(menu, menu->selected), colors);
432 }
433 
434 
draw_menu(const WMenu * menu,bool complete)435 void draw_menu(const WMenu *menu, bool complete)
436 {
437 	WGRData *grdata=GRDATA;
438 	Window win=menu->menu_win;
439 	const WMenuData *data=menu->data;
440 	const WColorGroup *colors, *tcolors;
441 	int y=0, i, incr;
442 	WMenuEnt *ent;
443 
444 	if((WWinObj*)menu==wglobal.current_winobj){
445 		colors=&(grdata->act_base_colors);
446 		tcolors=&(grdata->act_tab_sel_colors);
447 	}else{
448 		colors=&(grdata->base_colors);
449 		tcolors=&(grdata->tab_sel_colors);
450 	}
451 
452 	if(complete){
453 		XSetWindowBackground(wglobal.dpy, menu->menu_win,
454 							 colors->pixels[WCG_PIX_BG]);
455 		XClearWindow(wglobal.dpy, win);
456 	}
457 
458 	if(!(menu->flags&WMENU_NOTITLE)){
459 		y=menu->title_height;
460 
461 		draw_box(win, GRDATA->gc, tcolors, 0, 0, menu->w, y, TRUE);
462 
463 		if(menu->flags&WMENU_KEEP){
464 			XSetForeground(wglobal.dpy, grdata->copy_gc,
465 						   tcolors->pixels[WCG_PIX_FG]);
466 			copy_masked(grdata, grdata->stick_pixmap, win,
467 						0, 0, grdata->stick_pixmap_w, grdata->stick_pixmap_h,
468 						menu->w-grdata->stick_pixmap_w-CF_BEVEL_WIDTH,
469 						CF_BEVEL_WIDTH);
470 		}
471 
472 		XSetForeground(wglobal.dpy, grdata->gc, tcolors->pixels[WCG_PIX_FG]);
473 		XDrawString(wglobal.dpy, win, grdata->gc, CF_MENUTITLE_H_SPACE,
474 					CF_MENUTITLE_V_SPACE+FONT_BASELINE(grdata->font),
475 					data->title, strlen(data->title));
476 
477 	}
478 
479 	incr=menu->entry_height;
480 
481 	draw_box(win, GRDATA->gc, colors, 0, y, menu->w, menu->h-y, complete);
482 
483 	XSetForeground(wglobal.dpy, grdata->menu_gc, colors->pixels[WCG_PIX_FG]);
484 
485 	y+=CF_MENU_V_SPACE;
486 
487 	for(i=0, ent=data->entries; i<data->nentries; i++, y+=incr, ent++){
488 		if(i==menu->selected)
489 			continue;
490 		draw_menu_entrytext(menu, grdata, y, ent);
491 	}
492 
493 	draw_menu_selection(menu);
494 }
495 
496 
draw_frame(const WFrame * frame,bool complete)497 void draw_frame(const WFrame *frame, bool complete)
498 {
499 	draw_frame_frame(frame, complete);
500 	draw_frame_bar(frame, complete);
501 }
502 
503 
draw_dock(const WDock * dock,bool complete)504 void draw_dock(const WDock *dock, bool complete)
505 {
506 	if(complete)
507 		XClearWindow(wglobal.dpy, dock->win);
508 
509 	draw_box(dock->win, GRDATA->gc, &(GRDATA->base_colors), 0, 0,
510 			 dock->w, dock->h, FALSE);
511 }
512