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