swk

static widget kit
git clone git://git.suckless.org/swk
Log | Files | Refs | README | LICENSE

gi_x11.c (7601B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <stdlib.h>
      5 #include <ctype.h>
      6 #include <locale.h>
      7 #include <X11/keysym.h>
      8 #include <X11/Xlib.h>
      9 #include <X11/Xutil.h>
     10 #include <dc.h>
     11 #include "swk.h"
     12 #define SWK
     13 #include "config.h"
     14 
     15 //#define FONTNAME "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*"
     16 #define FONTNAME "--10x20"
     17 
     18 static int fs = FONTSIZE; // TODO: we need fsW and fsH
     19 static Window window;
     20 static XWindowAttributes wa;
     21 static DC *dc = NULL;
     22 static int col[ColorLast];
     23 static int colors[ColorLast] = { FGCOLOR, BGCOLOR, HICOLOR, TFCOLOR, CCCOLOR };
     24 #define EVENTMASK PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask
     25 
     26 static void dc_window_title(Window w, const char *title) {
     27 	XSetStandardProperties(dc->dpy, window, title, NULL, None, NULL, 0, NULL);
     28 }
     29 
     30 int
     31 swk_gi_fontsize(int sz) {
     32 	fs += sz*2;
     33 	/* TODO: resize font */
     34 	return 1;
     35 }
     36 
     37 int
     38 swk_gi_init(SwkWindow *w) {
     39 	char buf[128];
     40 	int i;
     41 	if (dc) return 0;
     42 	dc = dc_init();
     43 	for(i=0;i<ColorLast;i++) {
     44 		sprintf(buf, "#%06x", colors[i]);
     45 		col[i] = dc_color(dc, buf);
     46 	}
     47 	dc_font(dc, FONTNAME);
     48 	// TODO: must be dc_window(dc, x, y, w, h, bg, fg)
     49 	window = dc_window(dc, 10, 10, w->r.w, w->r.h);
     50 	XSelectInput(dc->dpy, window, EVENTMASK);
     51 	dc_window_title(window, w->title);
     52 	return swk_gi_fontsize(0);
     53 }
     54 
     55 int
     56 swk_gi_update(SwkWindow *w) {
     57 	XWindowAttributes wa;
     58 	XGetWindowAttributes(dc->dpy, window, &wa);
     59 	w->r.w = (wa.width / fs)-1;
     60 	w->r.h = (wa.height / fs)-1;
     61 	return 1;
     62 }
     63 
     64 void
     65 swk_gi_exit() {
     66 	dc_free(dc);
     67 	dc = NULL;
     68 }
     69 
     70 SwkEvent *
     71 swk_gi_event(SwkWindow *w, int dowait) {
     72 	static int mousedowny, mousedownx, mousedown = 0;
     73 	KeySym ksym;
     74 	XEvent event;
     75 	SwkEvent *ret = &w->_e;
     76 
     77 	if(!dowait && !XPending(dc->dpy))
     78 		return NULL;
     79 	XNextEvent(dc->dpy, &event);
     80 	switch(event.type) {
     81 	case Expose:
     82 		ret->type = EExpose;
     83 		ret->data.expose.x = ret->data.expose.y = \
     84 		ret->data.expose.w = ret->data.expose.h = 0;
     85 		break;
     86 	case MotionNotify:
     87 		// TODO: move this stuff into swk.c.. shoudlnt be backend dependent
     88 //		fprintf(stderr, "event: motion (%d,%d)\n", event.motion.x,event.motion.y);
     89 		if(mousedown) {
     90 			if(event.xmotion.y>mousedowny+fs) {
     91 				mousedowny = event.xmotion.y;
     92 				swk_scroll_up(w);
     93 			} else
     94 			if(event.xmotion.y<mousedowny-fs) {
     95 				mousedowny = event.xmotion.y;
     96 				swk_scroll_down(w);
     97 			}
     98 			if(event.xmotion.x>mousedownx+fs) {
     99 				mousedownx = event.xmotion.x;
    100 				swk_column_move_right();
    101 				swk_column_move_right();
    102 			} else
    103 			if(event.xmotion.x<mousedownx-fs) {
    104 				mousedownx = event.xmotion.x;
    105 				swk_column_move_left();
    106 				swk_column_move_left();
    107 			}
    108 			ret->type = EExpose;
    109 			ret->data.expose.x = ret->data.expose.y = \
    110 			ret->data.expose.w = ret->data.expose.h = 0;
    111 		} else {
    112 			ret->type = EMotion;
    113 			ret->data.motion.x = event.xmotion.x / fs;
    114 			ret->data.motion.y = event.xmotion.y / fs;
    115 		}
    116 		break;
    117 	case ButtonRelease:
    118 		//fprintf(stderr, "event: up %d (%d,%d)\n", event.button.button,event.button.x,event.button.y);
    119 		mousedown = 0;
    120 		ret->type = EClick;
    121 		switch(event.xbutton.state) {
    122 		case 4096: // 0x1000
    123 			ret->data.click.button = 4;
    124 			break;
    125 		case 2048: // 0x800
    126 			ret->data.click.button = 5;
    127 			break;
    128 		case 1024: // 0x400
    129 			ret->data.click.button = 2;
    130 			break;
    131 		case 512: // 0x200
    132 			ret->data.click.button = 3;
    133 			break;
    134 		case 256: // 0x100
    135 			ret->data.click.button = 1;
    136 			break;
    137 		}
    138 		ret->data.click.point.x = event.xbutton.x / fs;
    139 		ret->data.click.point.y = event.xbutton.y / fs;
    140 		break;
    141 	case ButtonPress:
    142 		//fprintf(stderr, "event: down %d (%d,%d)\n", event.button.button,event.button.x,event.button.y);
    143 		mousedown = 1;
    144 		mousedowny = event.xbutton.y;
    145 		break;
    146 	case KeyPress:
    147 		ret->type = EKey;
    148 		XLookupString(&event.xkey, NULL, 0, &ksym, NULL);
    149 		printf("ksym=%d\n", (int)ksym);
    150 
    151 		switch(ksym) {
    152 		case 65535: // supr
    153 			ret->data.key.keycode = 127;
    154 			break;
    155 		case 65511:
    156 			ret->data.key.keycode = KUp;
    157 			break;
    158 		case 65362:
    159 			ret->data.key.keycode = KUp;
    160 			break;
    161 		case 65364:
    162 			ret->data.key.keycode = KDown;
    163 			break;
    164 		case 65361:
    165 			ret->data.key.keycode = KLeft;
    166 			break;
    167 		case 65363:
    168 			ret->data.key.keycode = KRight;
    169 			break;
    170 		case XK_BackSpace:
    171 			ret->data.key.keycode = 8;
    172 			break;
    173 		case XK_Return:
    174 			ret->data.key.keycode = '\n';
    175 			break;
    176 		default:
    177 			ret->data.key.keycode = ksym;
    178 		}
    179 		ret->data.key.modmask = 0;
    180 		if(event.xkey.state&ShiftMask)
    181 			ret->data.key.modmask |= Shift;
    182 		if(event.xkey.state&Mod1Mask)
    183 			ret->data.key.modmask |= Alt;
    184 		if(event.xkey.state&ControlMask)
    185 			ret->data.key.modmask |= Ctrl;
    186 		fprintf(stderr, "event: key %d %d (%c)\n", 
    187 			ret->data.key.modmask, ret->data.key.keycode, ret->data.key.keycode);
    188 		break;
    189 	case 0:
    190 		ret->type = EQuit;
    191 		break;
    192 	default:
    193 		ret = NULL;
    194 		break;
    195 	}
    196 	return ret;
    197 }
    198 
    199 void
    200 swk_gi_clear() {
    201 	Rect r = {0};
    202 	XGetWindowAttributes(dc->dpy, window, &wa);
    203 	dc_resize(dc, wa.width, wa.height);
    204 	r.w = wa.width; // TODO: propagate those values into SwkWindow?
    205 	r.h = wa.height;
    206 	swk_gi_fill(r, ColorBG, 0);
    207 }
    208 
    209 void
    210 swk_gi_flip() {
    211 	dc_map(dc, window, wa.width, wa.height);
    212 }
    213 
    214 /* -- drawing primitives -- */
    215 void
    216 swk_gi_line(int x1, int y1, int x2, int y2, int color) {
    217 	XSetForeground(dc->dpy, dc->gc, col[color]);
    218 	XDrawLine(dc->dpy, dc->canvas, dc->gc, x1*fs, y1*fs, (x1+x2)*fs, (y1+y2)*fs);
    219 }
    220 
    221 void
    222 swk_gi_fill(Rect r, int color, int lil) {
    223 	XRectangle area = { r.x*fs, r.y*fs, r.w*fs, r.h*fs };
    224 	if(lil==1) {
    225 		int s = fs/4;
    226 		area.x += s;
    227 		area.y += s;
    228 		area.width -= (s*2);
    229 		area.height -= (s*2);
    230 	} else
    231 	if(lil==2) {
    232 		area.x/=3;
    233 		area.x-=2;
    234 		area.width=2;///=4;
    235 		area.y+=4;
    236 		area.height-=4;
    237 	} else if (lil==3) {
    238 		const int s = fs/4;
    239 		area.width -= (s*2);
    240 		area.height -= (s*4);
    241 	}
    242 	if(area.width<1) area.width = 1;
    243 	if(area.height<1) area.height = 1;
    244 	XSetForeground(dc->dpy, dc->gc, col[color]);
    245 	XFillRectangles(dc->dpy, dc->canvas, dc->gc, &area, 1);
    246 }
    247 
    248 void
    249 swk_gi_rect(Rect r, int color) {
    250 	swk_gi_line(r.x, r.y, r.w, 0, color);
    251 	swk_gi_line(r.x, r.y+r.h, r.w, 0, color);
    252 	swk_gi_line(r.x, r.y, 0, r.h, color);
    253 	swk_gi_line(r.x+r.w, r.y, 0, r.h, color);
    254 }
    255 
    256 void
    257 swk_gi_text(Rect r, const char *text) {
    258 	if(!text||!*text)
    259 		return;
    260 	XSetForeground(dc->dpy, dc->gc, col[ColorFG]);
    261 	// TODO: use libdraw to get length of string and support utf8..
    262 	// TODO: retrieve character width before rendering
    263 	XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc,
    264 		5+(r.x*fs), ((r.y+1)*fs-3), text, strlen(text));
    265 }
    266 
    267 void
    268 swk_gi_img(Rect r, void *_img) {
    269 	SwkImage *img = _img;
    270 	if(img)
    271 		XPutImage(dc->dpy, dc->canvas, DefaultGC(dc->dpy, 0), img->pub,
    272 			0, 0, r.x*fs, r.y*fs, img->w, img->h);
    273 }
    274 
    275 void*
    276 swk_gi_img_new(int w, int h, int color) {
    277 	SwkImage *img = img_open(NULL);
    278 	img->w = w*fs;
    279 	img->h = h*fs;
    280 	img->bpp = 24;
    281 	img->priv = NULL;
    282 	*img->name = 0;
    283 	img->data = malloc(img->w*img->h*4);
    284 	memset(img->data, colors[color]&0xff, img->w*img->h*4);
    285 	img->pub = XCreateImage(dc->dpy, DefaultVisual(dc->dpy, 0), 24, ZPixmap,
    286 		0, img->data, img->w, img->h, 32, 0);
    287 	return img;
    288 }
    289 
    290 void*
    291 swk_gi_img_load(const char *str) {
    292 	SwkImage *img = img_open(str);
    293 	if (img == NULL)
    294 		return NULL;
    295 	img->pub = XCreateImage(dc->dpy, DefaultVisual(dc->dpy, 0), 24, ZPixmap,
    296 		0, img->data, img->w, img->h, 32, 0);
    297 	return img;
    298 }
    299 
    300 void
    301 swk_gi_img_free(void *s) {
    302 	img_free(s);
    303 }
    304 
    305 void
    306 swk_gi_img_set(void *_img, int x, int y, int color) {
    307 	SwkImage *img = _img;
    308 	int *ptr = img->data;
    309 	if(ptr) ptr[(y*img->w)+x] = color;
    310 }
    311 
    312 int
    313 swk_gi_img_get(void *_img, int x, int y) {
    314 	SwkImage *img = _img;
    315 	int *ptr = img->data;
    316 	return ptr?ptr[(y*img->w)+x]:0;
    317 }