2 xkbd - xlib based onscreen keyboard.
4 Copyright (C) 2001 Matthew Allum
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, or (at your option)
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.
24 #include <X11/keysymdef.h>
30 int max3( int a, int b, int c )
39 GC _createGC(Display *display, Window win)
42 unsigned long valuemask = 0;
44 unsigned int line_width = 1;
45 int line_style = LineSolid;
46 int cap_style = CapRound;
47 int join_style = JoinRound;
50 gc = XCreateGC(display, win, valuemask, &values);
51 XSetForeground(display, gc,
52 BlackPixel(display, DefaultScreen(display) ));
53 XSetBackground(display, gc,
54 WhitePixel(display, DefaultScreen(display) ));
56 XSetLineAttributes(display, gc, line_width, line_style,
57 cap_style, join_style );
59 XSetFillStyle(display, gc, FillSolid);
65 int _XColorFromStr(Display *display, XColor *col, const char *defstr)
68 const char delim[] = ",:";
73 if ((strchr(defstr, delim[0]) != NULL)
74 || (strchr(defstr, delim[1]) != NULL) )
76 token = strsep (&str, delim);
77 col->red = ( atoi(token) * 65535 ) / 255;
78 token = strsep (&str, delim);
79 col->green = ( atoi(token) * 65535 ) / 255;
80 token = strsep (&str, delim);
81 col->blue = ( atoi(token) * 65535 ) / 255;
83 return XAllocColor(display,
84 DefaultColormap(display, DefaultScreen(display)),
87 return XAllocNamedColor(display,
88 DefaultColormap(display, DefaultScreen(display)),
94 void button_set_bg_col(button *b, char *txt)
97 b->bg_gc = _createGC(b->kb->display, b->kb->win);
98 if (_XColorFromStr(b->kb->display, &col, txt) == 0)
100 perror("color allocation failed\n");
103 XSetForeground(b->kb->display, b->bg_gc, col.pixel );
107 void button_set_fg_col(button *b, char *txt)
110 b->fg_gc = _createGC(b->kb->display, b->kb->win);
111 if (_XColorFromStr(b->kb->display, &col, txt) == 0)
113 perror("color allocation failed\n");
116 XSetForeground(b->kb->display, b->fg_gc, col.pixel );
121 void button_set_pixmap(button *b, char *filename)
123 XpmAttributes attrib;
125 //unsigned long valuemask = 0;
127 b->pixmap = malloc(sizeof(Pixmap));
128 b->mask = malloc(sizeof(Pixmap));
130 attrib.valuemask = XpmCloseness;
131 attrib.closeness = 40000;
133 if (XpmReadFileToPixmap( b->kb->display, b->kb->win, filename,
134 b->pixmap, b->mask, &attrib)
137 fprintf(stderr, "xkbd: failed loading image '%s'\n", filename);
141 /* we'll also be needing a gc for transparency */
142 b->mask_gc = _createGC(b->kb->display,b->kb->win);
144 gc_vals.clip_mask = *(b->mask);
145 valuemask = GCClipMask;
146 XChangeGC(b->kb->display, b->mask_gc, valuemask, &gc_vals);
148 XSetForeground(b->kb->display, b->mask_gc,
149 WhitePixel(b->kb->display, DefaultScreen(b->kb->display) ));
150 XSetBackground(b->kb->display, b->mask_gc,
151 BlackPixel(b->kb->display, DefaultScreen(b->kb->display) ));
153 XSetClipMask(b->kb->display, b->mask_gc, *(b->mask));
155 b->c_width = attrib.width;
156 b->c_height = attrib.height;
160 void button_set_layout(button *b, char *txt)
162 b->layout_switch = atoi(txt);
165 void button_set_txt(button *b, char *txt)
167 b->default_txt = malloc(sizeof(char)*(strlen(txt)+1));
168 strcpy(b->default_txt,txt);
171 void button_set_txt_ks(button *b, char *txt)
173 if (strcmp(txt, "Caps_Lock") == 0 )
174 b->modifier = BUT_CAPS;
175 else if (strncmp(txt, "Shift", 5) == 0 )
176 b->modifier = BUT_SHIFT;
177 else if (strncmp(txt, "Control", 7) == 0 )
178 b->modifier = BUT_CTRL;
179 else if (strncmp(txt, "Alt", 3) == 0 )
180 b->modifier = BUT_ALT;
181 else if (strncmp(txt, "Meta", 4) == 0 )
182 b->modifier = BUT_META;
183 else if (strncmp(txt, "!Mod", 3) == 0 )
184 { b->modifier = BUT_MOD; b->default_ks = 0; return; }
186 if ((b->default_ks = XStringToKeysym(txt)) == (KeySym)NULL)
187 fprintf(stderr, "Cant find keysym for %s \n", txt);
189 /* for backwards compatibility */
190 if (b->default_ks >= 0x061 && b->default_ks <= 0x07a)
191 b->options |= OPT_OBEYCAPS;
194 void button_set_shift_txt(button *b, char *txt)
196 b->shift_txt = malloc(sizeof(char)*(strlen(txt)+1));
197 strcpy(b->shift_txt,txt);
200 void button_set_shift_ks(button *b, char *txt)
202 if ((b->shift_ks = XStringToKeysym(txt)) == (KeySym)NULL)
203 fprintf(stderr, "Cant find keysym for %s \n", txt);
206 void button_set_slide_ks(button *b, char *txt, int dir)
209 if ( (tmp_ks = XStringToKeysym(txt)) == 0) /* NoSymbol ?? */
211 fprintf(stderr, "Cant find keysym for %s \n", txt);
217 case UP : b->slide_up_ks = tmp_ks; break;
218 case DOWN : b->slide_down_ks = tmp_ks; break;
219 case LEFT : b->slide_left_ks = tmp_ks; break;
220 case RIGHT : b->slide_right_ks = tmp_ks; break;
224 void button_set_scancode(button *b, char *txt)
226 b->scancode = atoi(txt);
229 void button_set_mod_txt(button *b, char *txt)
231 b->mod_txt = malloc(sizeof(char)*(strlen(txt)+1));
232 strcpy(b->mod_txt,txt);
235 void button_set_mod_ks(button *b, char *txt)
237 if ((b->mod_ks = XStringToKeysym(txt)) == (KeySym)NULL)
238 fprintf(stderr, "Cant find keysym for %s \n", txt);
241 int _button_get_txt_size(button *b, char *txt)
244 if (b->kb->render_type == xft)
247 XftTextExtentsUtf8(b->kb->display, b->kb->xftfont,
248 (unsigned char *) txt, strlen(txt),
250 return extents.width;
254 return XTextWidth(b->kb->font_info, txt, strlen(txt));
260 int button_calc_c_width(button *b)
262 int i = 0, j = 0, k = 0; // ouch - gotta be a better way
264 if (b->pixmap != NULL || b->c_width )
265 return b->c_width; /* already calculated from image or width_param */
267 if (b->default_txt != NULL)
268 i = _button_get_txt_size(b, b->default_txt);
269 if (b->shift_txt != NULL)
270 j = _button_get_txt_size(b, b->shift_txt);
271 if (b->mod_txt != NULL)
272 k = _button_get_txt_size(b, b->mod_txt);
274 b->c_width = max3( i,j,k );
278 int button_calc_c_height(button *b)
281 if (b->pixmap != NULL || b->c_height )
282 return b->c_height; /*already calculated from image or height param */
285 if (b->kb->render_type == xft)
288 b->kb->xftfont->height;
291 b->c_height = b->kb->font_info->ascent + b->kb->font_info->descent;
298 int button_get_c_height(button *b)
303 int button_set_b_size(button *b, int size)
309 void button_render(button *b, int mode)
312 set up a default gc to point to whatevers gc is not NULL
313 moving up via button -> box -> keyboard
325 x = button_get_abs_x(b) - b->kb->vbox->x;
326 y = button_get_abs_y(b) - b->kb->vbox->y;
329 if (mode == BUTTON_PRESSED)
332 gc_txt = b->kb->txt_gc;
334 tmp_col = b->kb->color_bg;
337 else if(mode == BUTTON_LOCKED)
340 gc_txt = b->kb->txt_rev_gc;
342 tmp_col = b->kb->color_bg;
345 else /* BUTTON_RELEASED */
348 gc_txt = b->kb->txt_gc;
350 tmp_col = b->kb->color_fg;
355 /* figure out what text to display
356 via keyboard state */
357 if ( b->kb->state != KB_STATE_NORMAL )
359 if ( (b->kb->state & KB_STATE_SHIFT
360 || b->kb->state & KB_STATE_CAPS )
361 && b->shift_txt != NULL )
363 if (b->kb->state & KB_STATE_CAPS
364 && b->kb->state & KB_STATE_SHIFT)
366 if (b->options & OPT_OBEYCAPS)
367 txt = b->default_txt;
371 else if (b->kb->state & KB_STATE_CAPS)
373 if (b->options & OPT_OBEYCAPS)
377 else txt = b->shift_txt;
379 else if ( b->kb->state & KB_STATE_MOD
380 && b->mod_txt != NULL )
386 if (txt == NULL) txt = b->default_txt;
388 if (!(b->default_ks || b->shift_ks || b->mod_ks) &&
389 ( b->default_txt == NULL && b->shift_txt == NULL && b->mod_txt == NULL)
391 return; /* its a 'blank' button - just a spacer */
393 /* -- but color gc1*/
394 XFillRectangle( b->kb->display, b->kb->backing, gc_solid,
395 x, y, b->act_width, b->act_height );
398 if (b->kb->theme != plain)
399 XDrawRectangle( b->kb->display, b->kb->backing, b->kb->bdr_gc,
400 x, y, b->act_width, b->act_height );
402 if (b->kb->theme == rounded)
404 XDrawPoint( b->kb->display, b->kb->backing, b->kb->bdr_gc, x+1, y+1);
405 XDrawPoint( b->kb->display, b->kb->backing,
406 b->kb->bdr_gc, x+b->act_width-1, y+1);
407 XDrawPoint( b->kb->display, b->kb->backing,
408 b->kb->bdr_gc, x+1, y+b->act_height-1);
409 XDrawPoint( b->kb->display, b->kb->backing,
410 b->kb->bdr_gc, x+b->act_width-1,
414 if (b->pixmap != NULL)
416 /* TODO: improve alignment of images, kinda hacked at the mo ! */
418 unsigned long valuemask = 0;
421 XSetClipMask(b->kb->display, b->mask_gc,*(b->mask));
423 gc_vals.clip_x_origin = x+(b->x_pad/2)+b->b_size;
424 gc_vals.clip_y_origin = y+b->c_height+(b->y_pad/2) +
425 b->b_size-b->c_height +2;
426 valuemask = GCClipXOrigin | GCClipYOrigin ;
427 XChangeGC(b->kb->display, b->mask_gc, valuemask, &gc_vals);
429 XCopyArea(b->kb->display, *(b->pixmap), b->kb->backing, b->mask_gc,
431 b->c_height, x+(b->x_pad/2)+b->b_size,
432 y +b->c_height+(b->y_pad/2) -b->c_height + b->b_size+2
434 return; /* imgs cannot have text aswell ! */
439 //if (b->c_width > _button_get_txt_size(b,txt))
440 xspace = x+((b->act_width - _button_get_txt_size(b,txt))/2);
442 //xspace = x+((b->c_width)/2);
443 //xspace = x+(b->x_pad/2)+b->b_size;
445 if (b->kb->render_type == xft)
447 int y_offset = ((b->c_height + b->y_pad) - b->kb->xftfont->height)/2;
448 XftDrawStringUtf8(b->kb->xftdraw, &tmp_col, b->kb->xftfont,
449 /*x+(b->x_pad/2)+b->b_size, */
451 /* y + b->c_height + b->b_size + (b->y_pad/2) - 4 */
452 y + y_offset + b->kb->xftfont->ascent ,
453 /* y+b->c_height+(b->y_pad/2)-b->b_size, */
454 (unsigned char *) txt, strlen(txt));
460 b->kb->display, b->kb->backing, gc_txt,
461 /*x+(b->x_pad/2)+b->b_size,*/
463 y+b->c_height+(b->y_pad/2)+b->b_size
472 void button_paint(button *b)
474 /* use the vbox offsets for the location within the window */
475 int x = button_get_abs_x(b) - b->kb->vbox->x;
476 int y = button_get_abs_y(b) - b->kb->vbox->y;
478 XCopyArea(b->kb->display, b->kb->backing, b->kb->win, b->kb->gc,
479 x, y, b->act_width, b->act_height,
480 x+b->kb->vbox->x, y+b->kb->vbox->y);
483 int button_get_abs_x(button *b)
486 box *tmp_box = b->parent;
487 while (tmp_box != NULL)
490 tmp_box = tmp_box->parent;
492 /* total = total - b->kb->vbox->x; HACK ! */
497 int button_get_abs_y(button *b)
500 box *tmp_box = b->parent;
501 while (tmp_box != NULL)
504 tmp_box = tmp_box->parent;
510 button* button_new(keyboard *k)
513 b = malloc(sizeof(button));
515 b->default_txt = NULL;
519 b->default_ks = 0; /* I hope 0 is safe ! */
524 b->slide_down_ks = 0;
525 b->slide_left_ks = 0;
526 b->slide_right_ks = 0;
530 b->is_width_spec = False;
531 b->key_span_width = 0;
535 b->modifier = BUT_NORMAL;
536 b->options = OPT_NORMAL;
541 b->bg_gc = k->rev_gc;
543 b->layout_switch = -1;