Subversion Repositories Krakow BASIC

Rev

Rev 39 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
39 nishi 1
/* $Id: x11.c 40 2024-09-06 14:17:50Z nishi $ */
2
 
3
#include <stdbool.h>
4
#include <stddef.h>
5
#include <stdint.h>
40 nishi 6
#include <stdio.h>
7
#include <pthread.h>
8
#include <string.h>
9
#include <ctype.h>
10
#include <stdlib.h>
39 nishi 11
 
12
#include <X11/Xlib.h>
13
#include <X11/Xutil.h>
14
 
15
bool stop = false;
16
bool dorender = false;
40 nishi 17
bool renderall = false;
39 nishi 18
 
40 nishi 19
XExposeEvent ex;
20
 
21
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
22
 
23
#define FONTWIDTH 7
24
#define FONTHEIGHT 14
25
#define TEXTWIDTH 80
26
#define TEXTHEIGHT 25
39 nishi 27
int width;
28
int height;
29
 
40 nishi 30
uint8_t tram[TEXTWIDTH * TEXTHEIGHT];
31
uint8_t old_tram[TEXTWIDTH * TEXTHEIGHT];
32
 
39 nishi 33
GC gc;
34
Window w;
35
Display* d;
40 nishi 36
XFontStruct* font;
39 nishi 37
 
38
int bgc = 0;
39
int fgc = 15;
40
 
40 nishi 41
#define RGB(r,g,b) (((r) << 16) | ((g) << 8) | ((b) << 0))
42
 
39 nishi 43
uint32_t colors[] = {
40 nishi 44
	RGB(0, 0, 0),
45
	RGB(170, 0, 0),
46
	RGB(0, 170, 0),
47
	RGB(170, 85, 0),
48
	RGB(0, 0, 170),
49
	RGB(170, 0, 170),
50
	RGB(0, 170, 170),
51
	RGB(170, 170, 170),
52
	RGB(85, 85, 85),
53
	RGB(255, 85, 85),
54
	RGB(85, 255, 85),
55
	RGB(255, 255, 85),
56
	RGB(85, 85, 255),
57
	RGB(255, 85, 255),
58
	RGB(85, 255, 255),
59
	RGB(255, 255, 255)
39 nishi 60
};
61
 
40 nishi 62
/* NOTE: Called from outside */
63
void change_color(int a){
64
	pthread_mutex_lock(&mutex);
65
	fgc = (a >> 4) & 0xf;
66
	bgc = (a & 0xf);
67
	renderall = true;
68
	dorender = true;
69
	pthread_mutex_unlock(&mutex);
70
}
71
 
72
/* NOTE: Called from outside */
73
void clear(void){
74
	pthread_mutex_lock(&mutex);
75
	int i;
76
	for(i = 0; i < TEXTWIDTH * TEXTHEIGHT; i++){
77
		tram[i] = 0x20;
78
	}
79
	renderall = true;
80
	dorender = true;
81
	pthread_mutex_unlock(&mutex);
82
}
83
 
84
int cx = 0;
85
int cy = 0;
86
 
87
void scroll_y(void){
88
	cy = TEXTHEIGHT - 1;
89
	int i;
90
	for(i = TEXTWIDTH; i < TEXTWIDTH * TEXTHEIGHT; i++){
91
		tram[i - TEXTWIDTH] = tram[i];
92
	}
93
	for(i = 0; i < TEXTWIDTH; i++){
94
		tram[TEXTWIDTH * TEXTHEIGHT - TEXTWIDTH + i] = 0x20;
95
	}
96
}
97
 
98
#define maxmacro(a,b) ((a) > (b) ? (a) : (b))
99
#define minmacro(a,b) ((a) < (b) ? (a) : (b))
100
 
101
void putstr(const char* n){
102
	pthread_mutex_lock(&mutex);
103
	int i;
104
	ex.x = cx * TEXTWIDTH;
105
	ex.y = cy * TEXTHEIGHT;
106
	ex.width = TEXTWIDTH * FONTWIDTH;
107
	ex.height = 0;
108
	for(i = 0; n[i] != 0; i++){
109
		if(n[i] == '\n'){
110
			cy++;
111
			cx = 0;
112
			if(cy == TEXTHEIGHT){
113
				scroll_y();
114
				ex.height += FONTHEIGHT;
115
			}
116
		}else if(n[i] == 8){
117
			if(cx > 0) cx--;
118
		}else{
119
			tram[cy * TEXTWIDTH + cx++] = n[i];
120
			if(cx == TEXTWIDTH){
121
				cx = 0;
122
				cy++;
123
				if(cy == TEXTHEIGHT){
124
					scroll_y();
125
					ex.height += FONTHEIGHT;
126
				}
127
			}
128
		}
129
		ex.x = minmacro(ex.x, cx * TEXTWIDTH);
130
		ex.y = maxmacro(ex.y, cy * TEXTHEIGHT);
131
	}
132
	dorender = true;
133
	pthread_mutex_unlock(&mutex);
134
}
135
 
136
char x11_putchar(char c){
137
	char cbuf[2];
138
	cbuf[0] = c;
139
	cbuf[1] = 0;
140
	putstr(cbuf);
141
}
142
 
143
void putnum(int n){
144
	char number[512];
145
	sprintf(number, "%d", n);
146
	putstr(number);
147
}
148
 
149
char keybuffer[64];
150
 
151
char oggetch(char wait){
152
	char c;
153
	if(wait){
154
		while((c = keybuffer[0]) == 0);
155
	}else{
156
		c = keybuffer[0];
157
		if(c == 0) return 0;
158
	}
159
	pthread_mutex_lock(&mutex);
160
	int i;
161
	for(i = 1;; i++){
162
		keybuffer[i - 1] = keybuffer[i];
163
		if(keybuffer[i] == 0) break;
164
	}
165
	pthread_mutex_unlock(&mutex);
166
	return c;
167
}
168
 
39 nishi 169
void render(void){
40 nishi 170
	pthread_mutex_lock(&mutex);
171
	if(renderall){
172
		XSetForeground(d, gc, colors[bgc]);
173
		XFillRectangle(d, w, gc, 0, 0, width, height);
174
	}
175
 
176
 
177
	int y, x;
178
	char cbuf[2];
179
	cbuf[1] = 0;
180
	for(y = 0; y < TEXTHEIGHT; y++){
181
		for(x = 0; x < TEXTWIDTH; x++){
182
			cbuf[0] = tram[y * TEXTWIDTH + x];
183
			bool rnd = !renderall && old_tram[y * TEXTWIDTH + x] != cbuf[0];
184
			if(renderall || rnd){
185
				XSetForeground(d, gc, colors[bgc]);
186
				XFillRectangle(d, w, gc, x * FONTWIDTH, y * FONTHEIGHT, FONTWIDTH + 2, FONTHEIGHT + 2);
187
				XSetForeground(d, gc, colors[fgc]);
188
				XDrawString(d, w, gc, x * FONTWIDTH, y * FONTHEIGHT + FONTHEIGHT, cbuf, 1);
189
				if(rnd) old_tram[y * TEXTWIDTH + x] = cbuf[0];
190
			}
191
		}
192
	}
193
 
39 nishi 194
	XFlush(d);
40 nishi 195
	pthread_mutex_unlock(&mutex);
196
 
197
	if(renderall) renderall = false;
39 nishi 198
}
199
 
40 nishi 200
void x11_init(void){
201
	int i;
202
	for(i = 0; i < TEXTWIDTH * TEXTHEIGHT; i++){
203
		tram[i] = 0x20;
204
		old_tram[i] = 0xff;
205
	}
206
}
207
 
39 nishi 208
void* x11_thread(void* arg){
40 nishi 209
	width = FONTWIDTH * TEXTWIDTH;
210
	height = FONTHEIGHT * TEXTHEIGHT;
39 nishi 211
 
40 nishi 212
	int i;
213
	for(i = 0; i < 64; i++) keybuffer[i] = 0;
214
 
39 nishi 215
	d = XOpenDisplay(NULL);
216
	w = XCreateSimpleWindow(d, RootWindow(d, 0), 0, 0, width, height, 3, WhitePixel(d, 0), BlackPixel(d, 0));
217
	XStoreName(d, w, "Krakow BASIC");
218
 
219
	XSizeHints* size = XAllocSizeHints();
220
	size->flags = PMinSize | PMaxSize;
221
	size->min_width = size->max_width = width;
222
	size->min_height = size->max_height = height;
223
	XSetWMNormalHints(d, w, size);
224
	XFree(size);
225
 
40 nishi 226
	font = XLoadQueryFont(d, "7x14");
227
 
39 nishi 228
	XEvent ev;
229
 
40 nishi 230
	XSelectInput(d, w, ExposureMask | KeyPressMask | KeyReleaseMask);
39 nishi 231
	XMapWindow(d, w);
232
	XFlush(d);
233
 
234
	gc = XCreateGC(d, DefaultRootWindow(d), 0, 0);
40 nishi 235
	XSetFont(d, gc, font->fid);
39 nishi 236
 
40 nishi 237
	renderall = true;
39 nishi 238
	render();
239
 
240
	while(1){
241
		if(dorender){
242
			render();
243
			dorender = false;
244
		}else if(XPending(d) > 0){
245
			XNextEvent(d, &ev);
246
			if(ev.type == Expose){
40 nishi 247
				ex = ev.xexpose;
248
				renderall = true;
39 nishi 249
				render();
40 nishi 250
			}else if(ev.type == KeyPress){
251
				for(i = 0; keybuffer[i] != 0; i++);
252
				char* k_ = XKeysymToString(XLookupKeysym(&ev.xkey, 0));
253
				char* k = malloc(strlen(k_) + 1);
254
				memcpy(k, k_, strlen(k_));
255
				k[strlen(k_)] = 0;
256
				if(strcmp(k, "Return") == 0){
257
					k[0] = '\n';
258
				}else if(strcmp(k, "BackSpace") == 0){
259
					k[0] = '\x08';
260
				}else if(strcmp(k, "space") == 0){
261
					k[0] = ' ';
262
				}else if(strcmp(k, "comma") == 0){
263
					k[0] = ',';
264
				}else if(strcmp(k, "semicolon") == 0){
265
					k[0] = ';';
266
				}else if(strcmp(k, "c") == 0 && ev.xkey.state & ControlMask){
267
					k[0] = '\x01';
268
				}else if(strcmp(k, "1") == 0 && ev.xkey.state & ShiftMask){
269
					k[0] = '!';
270
				}else if(strcmp(k, "2") == 0 && ev.xkey.state & ShiftMask){
271
					k[0] = '"';
272
				}else if(strcmp(k, "3") == 0 && ev.xkey.state & ShiftMask){
273
					k[0] = '#';
274
				}else if(strcmp(k, "4") == 0 && ev.xkey.state & ShiftMask){
275
					k[0] = '$';
276
				}else if(strcmp(k, "5") == 0 && ev.xkey.state & ShiftMask){
277
					k[0] = '%';
278
				}else if(strcmp(k, "6") == 0 && ev.xkey.state & ShiftMask){
279
					k[0] = '&';
280
				}else if(strcmp(k, "7") == 0 && ev.xkey.state & ShiftMask){
281
					k[0] = '\'';
282
				}else if(strcmp(k, "8") == 0 && ev.xkey.state & ShiftMask){
283
					k[0] = '(';
284
				}else if(strcmp(k, "9") == 0 && ev.xkey.state & ShiftMask){
285
					k[0] = ')';
286
				}else if(strcmp(k, "0") == 0 && ev.xkey.state & ShiftMask){
287
					k[0] = '~';
288
				}else if(strcmp(k, "Control_L") == 0){
289
					k[0] = '\x00';
290
				}else if(strcmp(k, "Shift_L") == 0){
291
					k[0] = '\x00';
292
				}else if(strcmp(k, "Control_R") == 0){
293
					k[0] = '\x00';
294
				}else if(strcmp(k, "Shift_R") == 0){
295
					k[0] = '\x00';
296
				}else if(ev.xkey.state & ShiftMask){
297
					k[0] = toupper(k[0]);
298
				}
299
				keybuffer[i] = k[0];
300
				free(k);
39 nishi 301
			}
302
		}
303
	}
304
	stop = true;
305
	return arg;
306
}