Completely new build system for userspace
This commit is contained in:
parent
f0bc073bfe
commit
b2f94bd393
11
Makefile
11
Makefile
@ -23,6 +23,7 @@ DATASTRUCTS = $(patsubst %.c,%.o,$(wildcard kernel/ds/*.c))
|
||||
CPUBITS = $(patsubst %.c,%.o,$(wildcard kernel/cpu/*.c))
|
||||
|
||||
SUBMODULES = ${MODULES} ${FILESYSTEMS} ${VIDEODRIVERS} ${DEVICES} ${VIRTUALMEM} ${MISCMODS} ${SYSTEM} ${DATASTRUCTS} ${CPUBITS}
|
||||
USERSPACE = $(shell find userspace/ -type f -name '*.c') $(shell find userspace/ -type f -name '*.cpp') $(shell find userspace/ -type f -name '*.h')
|
||||
|
||||
UTILITIES = util/bin/readelf util/bin/typewriter util/bin/bim
|
||||
EMU = qemu-system-i386
|
||||
@ -138,15 +139,11 @@ toaruos-initrd: .passed
|
||||
hdd:
|
||||
@mkdir hdd
|
||||
|
||||
.userspace-check: userspace/*.c userspace/*.cpp userspace/lib/*.h userspace/lib/*.c
|
||||
@cd userspace && make
|
||||
.userspace-check: ${USERSPACE}
|
||||
@cd userspace && python build.py
|
||||
@touch .userspace-check
|
||||
|
||||
.compositor-check: toaru-compositor toaru-compositor/*.c
|
||||
@cd toaru-compositor && make
|
||||
@touch .compositor-check
|
||||
|
||||
toaruos-disk.img: hdd .userspace-check .compositor-check hdd/bin/*
|
||||
toaruos-disk.img: hdd .userspace-check hdd/bin/*
|
||||
@${BEG} "hdd" "Generating a Hard Disk image..."
|
||||
@-rm -f toaruos-disk.img
|
||||
@${GENEXT} -d hdd -q -b 131072 -N 4096 toaruos-disk.img ${ERRORS}
|
||||
|
@ -1,62 +0,0 @@
|
||||
CC = i686-pc-toaru-gcc
|
||||
CPP = i686-pc-toaru-g++
|
||||
CFLAGS = -std=c99 -U__STRICT_ANSI__ -O3 -m32 -Wa,--32
|
||||
CPPFLAGS = -O3 -m32 -Wa,--32
|
||||
ifeq ($(DEBUG_MODE),1)
|
||||
STRIP = true
|
||||
EXTRAFLAGS = -g
|
||||
else
|
||||
STRIP = i686-pc-toaru-strip
|
||||
EXTRAFLAGS = -s
|
||||
endif
|
||||
|
||||
EXECUTABLES = $(patsubst %.c,../hdd/bin/%,$(wildcard *.c))
|
||||
|
||||
BEG = ../util/mk-beg
|
||||
END = ../util/mk-end
|
||||
INFO = ../util/mk-info
|
||||
ERRORS = 2>>/tmp/.`whoami`-build-errors || ../util/mk-error
|
||||
ERRORSS = >>/tmp/.`whoami`-build-errors || ../util/mk-error
|
||||
|
||||
BEGRM = ../util/mk-beg-rm
|
||||
ENDRM = ../util/mk-end-rm
|
||||
|
||||
FREETYPE_INC = -I ${TOOLCHAIN}/include/freetype2/
|
||||
FREETYPE_LIB = ${TOOLCHAIN}/lib/libfreetype.a
|
||||
LIBPNG = ${TOOLCHAIN}/lib/libpng.a
|
||||
LIBM = ${TOOLCHAIN}/lib/libm.a
|
||||
LIBZ = ${TOOLCHAIN}/lib/libz.a
|
||||
|
||||
F_INCLUDES = ${FREETYPE_INC}
|
||||
F_LIBRARIES = ${FREETYPE_LIB} ${LIBPNG} ${LIBM} ${LIBZ}
|
||||
|
||||
CAIRO_INC = -I ${TOOLCHAIN}/include/cairo/
|
||||
CAIRO_LIB = ${TOOLCHAIN}/lib/libcairo.a
|
||||
PIXMAN_INC = -I ${TOOLCHAIN}/include/pixman-1/
|
||||
PIXMAN_LIB = ${TOOLCHAIN}/lib/libpixman-1.a
|
||||
|
||||
EXTRA_LIB_INCLUDES = ${F_INCLUDES} ${CAIRO_INC} ${PIXMAN_INC}
|
||||
EXTRA_LIB_LIBRARIES = ${F_LIBRARIES} ${CAIRO_LIB} ${PIXMAN_LIB}
|
||||
|
||||
LOCAL_LIBS = $(patsubst %.c,%.o,$(wildcard ../userspace/lib/*.c))
|
||||
LOCAL_INC = -I ../userspace/
|
||||
|
||||
TARGETDIR = ../hdd/bin/
|
||||
EXTRA_LIB_APPS = compositor2 cairo-demo pixman-demo make-it-snow ttk-demo
|
||||
EXTRA_LIB_TARGETS = $(EXTRA_LIB_APPS:%=$(TARGETDIR)%)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: ${EXECUTABLES}
|
||||
|
||||
clean:
|
||||
@${BEGRM} "RM" "Cleaning userspace full-toolchain applications."
|
||||
@-rm -f ${EXECUTABLES}
|
||||
@${ENDRM} "RM" "Cleaned userspace full-toolchain applications."
|
||||
|
||||
${EXTRA_LIB_TARGETS}: $(TARGETDIR)% : %.c
|
||||
@${BEG} "CC" "$< [w/extra libs]"
|
||||
@${CC} -flto ${CFLAGS} ${EXTRAFLAGS} ${LOCAL_INC} ${EXTRA_LIB_INCLUDES} -o $@ $< ${LOCAL_LIBS} ${EXTRA_LIB_LIBRARIES} ${ERRORS}
|
||||
@${STRIP} $@
|
||||
@${END} "CC" "$< [w/extra libs]"
|
||||
|
@ -1,17 +0,0 @@
|
||||
# とある Compositor (Cairo version)
|
||||
|
||||
This is a window compositor for [とあるOS](http://github.com/klange/osdev) using Cairo.
|
||||
|
||||
The normal compositor that ships with とあるOS uses a built-in alpha blitting mechanism. This one uses Cairo's rendering methods to draw windows, which is faster for alpha-enabled windows than the standard compositor, but slightly slower for non-alpha windows (as they are rendered as alpha-enabled regardless).
|
||||
|
||||
## Dependencies
|
||||
|
||||
Obviously, this needs Cairo. You may need to tweak some config.h options to get Cairo to build correctly.
|
||||
|
||||
Eventually, Cairo will be included in the standard toolchain.
|
||||
|
||||
## Installation
|
||||
|
||||
As with other external-library applications, clone this into your `osdev` repository, build its dependencies (Cairo, Pixman, etc.), run `make` and then `make clean-disk && make` in `osdev`.
|
||||
|
||||
You'll also need to change `init` so it runs `compositor2` instead of `compositor`.
|
@ -1,78 +0,0 @@
|
||||
CC = i686-pc-toaru-gcc
|
||||
CPP = i686-pc-toaru-g++
|
||||
CFLAGS = -std=c99 -U__STRICT_ANSI__ -O3 -m32 -Wa,--32
|
||||
CPPFLAGS = -O3 -m32 -Wa,--32
|
||||
ifeq ($(DEBUG_MODE),1)
|
||||
STRIP = true
|
||||
EXTRAFLAGS = -g
|
||||
else
|
||||
STRIP = i686-pc-toaru-strip
|
||||
EXTRAFLAGS = -s
|
||||
endif
|
||||
EXECUTABLES = $(patsubst %.c,%.o,$(wildcard lib/*.c)) $(patsubst %.c,../hdd/bin/%,$(wildcard *.c)) $(patsubst %.cpp,../hdd/bin/%,$(wildcard *.cpp))
|
||||
|
||||
BEG = ../util/mk-beg
|
||||
END = ../util/mk-end
|
||||
INFO = ../util/mk-info
|
||||
ERRORS = 2>>/tmp/.`whoami`-build-errors || ../util/mk-error
|
||||
ERRORSS = >>/tmp/.`whoami`-build-errors || ../util/mk-error
|
||||
|
||||
BEGRM = ../util/mk-beg-rm
|
||||
ENDRM = ../util/mk-end-rm
|
||||
|
||||
FREETYPE_INC = -I ${TOOLCHAIN}/include/freetype2/
|
||||
FREETYPE_LIB = ${TOOLCHAIN}/lib/libfreetype.a
|
||||
LIBPNG = ${TOOLCHAIN}/lib/libpng.a
|
||||
LIBM = ${TOOLCHAIN}/lib/libm.a
|
||||
LIBZ = ${TOOLCHAIN}/lib/libz.a
|
||||
|
||||
TARGETDIR = ../hdd/bin/
|
||||
ETARGETS = terminal login compositor view game drawlines glogin julia solver wallpaper panel glock clock-win draw test-gfx threadtest bim blur_test test-borders serial-console ls plasma
|
||||
FTARGETS = $(ETARGETS:%=$(TARGETDIR)%)
|
||||
|
||||
LOCAL_LIBS = $(patsubst %.c,%.o,$(wildcard lib/*.c))
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: ${EXECUTABLES}
|
||||
|
||||
clean:
|
||||
@${BEGRM} "RM" "Cleaning userspace full-toolchain applications."
|
||||
@-rm -f ${EXECUTABLES}
|
||||
@${ENDRM} "RM" "Cleaned userspace full-toolchain applications."
|
||||
|
||||
${FTARGETS}: $(TARGETDIR)% : %.c ${LOCAL_LIBS}
|
||||
@${BEG} "CC" "$< [w/libs]"
|
||||
@${CC} -flto ${CFLAGS} ${EXTRAFLAGS} ${FREETYPE_INC} -o $@ $< ${LOCAL_LIBS} ${LIBM} ${FREETYPE_LIB} ${LIBPNG} ${LIBZ} ${ERRORS}
|
||||
@${STRIP} $@
|
||||
@${END} "CC" "$< [w/libs]"
|
||||
|
||||
$(TARGETDIR)%: %.cpp
|
||||
@${BEG} "CPP" "$<"
|
||||
@${CPP} ${CPPFLAGS} ${EXTRAFLAGS} -o $@ $< ${ERRORS}
|
||||
@${END} "CPP" "$<"
|
||||
|
||||
$(TARGETDIR)ld: ld.c lib/ldlib.o
|
||||
@${BEG} "CC" "$< [-fPIC]"
|
||||
@${CC} ${CFLAGS} ${EXTRAFLAGS} -fPIC -o $@ $< lib/ldlib.o ${ERRORS}
|
||||
@${END} "CC" "$< [-fPIC]"
|
||||
|
||||
$(TARGETDIR)%: %.c
|
||||
@${BEG} "CC" "$<"
|
||||
@${CC} ${CFLAGS} ${EXTRAFLAGS} -o $@ $< ${ERRORS}
|
||||
@${END} "CC" "$<"
|
||||
|
||||
$(TARGETDIR)esh: esh.c lib/list.o lib/kbd.o
|
||||
@${BEG} "CC" "$<"
|
||||
@${CC} ${CFLAGS} ${EXTRAFLAGS} -o $@ $< lib/list.o lib/kbd.o ${ERRORS}
|
||||
@${END} "CC" "$<"
|
||||
|
||||
lib/shmemfonts.o: lib/shmemfonts.c
|
||||
@${BEG} "CC" "$< [lib]"
|
||||
@${CC} ${CFLAGS} -c ${EXTRAFLAGS} ${FREETYPE_INC} -o $@ $< ${ERRORS}
|
||||
@${END} "CC" "$< [lib]"
|
||||
|
||||
%.o: %.c
|
||||
@${BEG} "CC" "$< [lib]"
|
||||
@${CC} ${CFLAGS} -c ${EXTRAFLAGS} -o $@ $< ${ERRORS}
|
||||
@${END} "CC" "$< [lib]"
|
203
userspace/build.py
Normal file
203
userspace/build.py
Normal file
@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JuJu - An automagical compiler for the とあるOS userspace.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
TOOLCHAIN_PATH = os.environ['TOOLCHAIN']
|
||||
|
||||
class CCompiler(object):
|
||||
extension = 'c'
|
||||
compiler = 'i686-pc-toaru-gcc'
|
||||
dependency_hints = {
|
||||
'<cairo.h>': ('cairo', '-lcairo', ['<ft2build.h>', '<pixman.h>']),
|
||||
'<ft2build.h>': ('freetype2', '-lfreetype', []),
|
||||
'<pixman.h>': ('pixman-1', '-lpixman-1', []),
|
||||
'<zlib.h>': (None, '-lz', ['<math.h>']),
|
||||
'<png.h>': (None, '-lpng', ['<zlib.h>']),
|
||||
'<math.h>': (None, TOOLCHAIN_PATH + '/lib/libm.a', []),
|
||||
'"lib/decorations.h"': (None, 'lib/decorations.o', ['"lib/shmemfonts.h"', '"lib/graphics.h"', '"lib/window.h"']),
|
||||
'"lib/graphics.h"': (None, 'lib/graphics.o', ['<png.h>']),
|
||||
'"lib/kbd.h"': (None, 'lib/kbd.o', []),
|
||||
'"lib/list.h"': (None, 'lib/list.o', []),
|
||||
'"lib/pthread.h"': (None, 'lib/pthread.o', []),
|
||||
'"lib/sha2.h"': (None, 'lib/sha2.o', []),
|
||||
'"lib/shmemfonts.h"': (None, 'lib/shmemfonts.o', ['"lib/graphics.h"', '<ft2build.h>']),
|
||||
'"lib/wcwidth.h"': (None, 'lib/wcwidth.o', []),
|
||||
'"lib/window.h"': (None, 'lib/window.o', ['"lib/pthread.h"', '"lib/list.h"']),
|
||||
}
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.arguments = ['-std=c99', '-U__STRICT_ANSI__', '-O3', '-m32', '-Wa,--32', '-g', '-I.']
|
||||
if '/lib/' in filename:
|
||||
self.includes, _ = self._depends()
|
||||
self.libs = []
|
||||
self.arguments.extend(self.includes)
|
||||
self.arguments.extend(['-c', '-o', self.output_file(), filename])
|
||||
else:
|
||||
self.includes, self.libs = self._depends()
|
||||
self.arguments.extend(self.includes)
|
||||
self.arguments.extend(['-flto', '-o', self.output_file(), filename])
|
||||
self.arguments.extend(self.libs)
|
||||
|
||||
def dependencies(self):
|
||||
return [os.path.abspath(x) for x in self.libs if x.startswith('lib/')]
|
||||
|
||||
def output_file(self):
|
||||
if '/lib/' in self.filename:
|
||||
return os.path.abspath(self.filename.replace('.c','.o'))
|
||||
else:
|
||||
return os.path.abspath('../hdd/bin/' + os.path.basename(self.filename).replace('.c',''))
|
||||
|
||||
def _calculate(self, depends, new):
|
||||
for k in new:
|
||||
if not k in depends:
|
||||
depends.append(k)
|
||||
_, _, other = self.dependency_hints[k]
|
||||
depends = self._calculate(depends, other)
|
||||
return depends
|
||||
|
||||
def _depends(self):
|
||||
lines = []
|
||||
depends = []
|
||||
with open(self.filename) as f:
|
||||
lines = f.readlines()
|
||||
for l in lines:
|
||||
if l.startswith('#include'):
|
||||
depends.extend([k for k in self.dependency_hints.keys() if l.startswith('#include ' + k)])
|
||||
depends = self._calculate([], depends)
|
||||
includes = []
|
||||
libraries = []
|
||||
for k in depends:
|
||||
dep = self.dependency_hints[k]
|
||||
if dep[0]:
|
||||
includes.append('-I' + TOOLCHAIN_PATH + '/include/' + dep[0])
|
||||
if dep[1]:
|
||||
libraries.append(dep[1])
|
||||
return includes, libraries
|
||||
|
||||
def notify_start(self):
|
||||
subprocess.call(['../util/mk-beg', 'CC', self.filename])
|
||||
def notify_done(self):
|
||||
subprocess.call(['../util/mk-end', 'CC', self.filename])
|
||||
|
||||
class CXXCompiler(CCompiler):
|
||||
extension = 'cpp'
|
||||
compiler = 'i686-pc-toaru-g++'
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.arguments = ['-O3', '-m32', '-Wa,--32', '-g', '-I.']
|
||||
if '/lib/' in filename:
|
||||
self.includes, _ = self._depends()
|
||||
self.libs = []
|
||||
self.arguments.extend(self.includes)
|
||||
self.arguments.extend(['-c', '-o', self.output_file(), filename])
|
||||
else:
|
||||
self.includes, self.libs = self._depends()
|
||||
self.arguments.extend(self.includes)
|
||||
self.arguments.extend(['-flto', '-o', self.output_file(), filename])
|
||||
self.arguments.extend(self.libs)
|
||||
|
||||
def output_file(self):
|
||||
if '/lib/' in self.filename:
|
||||
return os.path.abspath(self.filename.replace('.cpp','.o'))
|
||||
else:
|
||||
return os.path.abspath('../hdd/bin/' + os.path.basename(self.filename).replace('.cpp',''))
|
||||
|
||||
def notify_start(self):
|
||||
subprocess.call(['../util/mk-beg', 'CPP', self.filename])
|
||||
def notify_done(self):
|
||||
subprocess.call(['../util/mk-end', 'CPP', self.filename])
|
||||
|
||||
source_extensions = {'c': CCompiler, 'cpp': CXXCompiler}
|
||||
|
||||
def find_sources(path):
|
||||
sources = []
|
||||
for directory, subdirectories, files in os.walk(path):
|
||||
for f in files:
|
||||
for k, v in source_extensions.iteritems():
|
||||
if f.endswith('.' + k):
|
||||
sources.append((directory + '/' + f, v))
|
||||
return sources
|
||||
|
||||
sources = {}
|
||||
for source, compiler in find_sources('.'):
|
||||
sources[os.path.abspath(source)] = compiler(source)
|
||||
|
||||
outputs = {}
|
||||
outputs_r = {}
|
||||
for k,v in sources.iteritems():
|
||||
outputs[k] = v.output_file()
|
||||
outputs_r[outputs[k]] = k
|
||||
|
||||
marked = []
|
||||
rounds = []
|
||||
remaining = outputs_r.keys()
|
||||
|
||||
def satisfied():
|
||||
return len(remaining) == 0
|
||||
|
||||
while not satisfied():
|
||||
this_round = []
|
||||
for target in [x for x in outputs_r.keys() if x not in marked]:
|
||||
x = sources[outputs_r[target]]
|
||||
if all([(y in marked) for y in x.dependencies()]):
|
||||
marked.append(target)
|
||||
remaining.remove(target)
|
||||
this_round.append(target)
|
||||
else:
|
||||
for y in [dep for dep in x.dependencies() if not dep in marked]:
|
||||
if not y in remaining:
|
||||
remaining.append(y)
|
||||
if not this_round and not satisfied():
|
||||
raise Exception("Dependency resolution error.")
|
||||
rounds.append(this_round)
|
||||
|
||||
needs_rebuild = []
|
||||
for r in rounds:
|
||||
for target in r:
|
||||
source = outputs_r[target]
|
||||
source_obj = sources[source]
|
||||
if not os.path.exists(target):
|
||||
needs_rebuild.append(target)
|
||||
elif os.path.getmtime(target) < os.path.getmtime(source):
|
||||
needs_rebuild.append(target)
|
||||
elif [True for x in source_obj.dependencies() if x in needs_rebuild]:
|
||||
needs_rebuild.append(target)
|
||||
elif [True for x in source_obj.dependencies() if os.path.exists(target) and (os.path.getmtime(target) < os.path.getmtime(x))]:
|
||||
needs_rebuild.append(target)
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'status':
|
||||
if not needs_rebuild:
|
||||
print "Nothing to do."
|
||||
elif len(needs_rebuild) == 1:
|
||||
print "One file needs rebuilding."
|
||||
else:
|
||||
print len(needs_rebuild), "file(s) need rebuilding."
|
||||
elif len(sys.argv) > 1 and sys.argv[1] == 'clean':
|
||||
for i in outputs_r.keys():
|
||||
subprocess.call(['../util/mk-beg-rm', 'RM', i])
|
||||
subprocess.call(['rm', i])
|
||||
subprocess.call(['../util/mk-end-rm', 'RM', i])
|
||||
else:
|
||||
if not needs_rebuild:
|
||||
print "Nothing to do."
|
||||
else:
|
||||
for target in needs_rebuild:
|
||||
source_obj = sources[outputs_r[target]]
|
||||
cmd = [source_obj.compiler]
|
||||
cmd.extend(source_obj.arguments)
|
||||
source_obj.notify_start()
|
||||
ret = subprocess.call(cmd)
|
||||
source_obj.notify_done()
|
||||
if ret:
|
||||
print target, ret
|
||||
print cmd
|
||||
raise Exception
|
||||
|
@ -1,938 +0,0 @@
|
||||
/*
|
||||
* Compositor
|
||||
*
|
||||
* This is the window compositor application.
|
||||
* It serves shared memory regions to clients
|
||||
* and renders them to the screen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lib/list.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/window.h"
|
||||
#include "lib/pthread.h"
|
||||
#include "lib/kbd.h"
|
||||
|
||||
#include "../kernel/include/signal.h"
|
||||
#include "../kernel/include/mouse.h"
|
||||
|
||||
#define SINGLE_USER_MODE 0
|
||||
#define FORCE_UID 1000
|
||||
#define SPRITE_COUNT 2
|
||||
#define WIN_D 32
|
||||
#define WIN_B (WIN_D / 8)
|
||||
#define MOUSE_DISCARD_LEVEL 10
|
||||
#define MOUSE_SCALE 3
|
||||
#define MOUSE_OFFSET_X 26
|
||||
#define MOUSE_OFFSET_Y 26
|
||||
#define SPRITE_MOUSE 1
|
||||
#define WINDOW_LAYERS 0x10000
|
||||
#define FONT_PATH "/usr/share/fonts/"
|
||||
#define FONT(a,b) {WINS_SERVER_IDENTIFIER ".fonts." a, FONT_PATH b}
|
||||
|
||||
struct font_def {
|
||||
char * identifier;
|
||||
char * path;
|
||||
};
|
||||
|
||||
/* Non-public bits from window.h */
|
||||
extern window_t * init_window (process_windows_t * pw, wid_t wid, int32_t x, int32_t y, uint16_t width, uint16_t height, uint16_t index);
|
||||
extern void free_window (window_t * window);
|
||||
extern void resize_window_buffer (window_t * window, int16_t left, int16_t top, uint16_t width, uint16_t height);
|
||||
extern FILE *fdopen(int fd, const char *mode);
|
||||
|
||||
window_t * focused = NULL;
|
||||
window_t * windows[WINDOW_LAYERS];
|
||||
sprite_t * sprites[SPRITE_COUNT];
|
||||
gfx_context_t * ctx;
|
||||
list_t * process_list;
|
||||
int32_t mouse_x, mouse_y;
|
||||
int32_t click_x, click_y;
|
||||
uint32_t mouse_discard = 0;
|
||||
volatile int am_drawing = 0;
|
||||
window_t * moving_window = NULL;
|
||||
int32_t moving_window_l = 0;
|
||||
int32_t moving_window_t = 0;
|
||||
window_t * resizing_window = NULL;
|
||||
int32_t resizing_window_w = 0;
|
||||
int32_t resizing_window_h = 0;
|
||||
wid_t volatile _next_wid = 1;
|
||||
wins_server_global_t volatile * _request_page;
|
||||
int error;
|
||||
|
||||
struct font_def fonts[] = {
|
||||
FONT("sans-serif", "DejaVuSans.ttf"),
|
||||
FONT("sans-serif.bold", "DejaVuSans-Bold.ttf"),
|
||||
FONT("sans-serif.italic", "DejaVuSans-Oblique.ttf"),
|
||||
FONT("sans-serif.bolditalic", "DejaVuSans-BoldOblique.ttf"),
|
||||
FONT("monospace", "DejaVuSansMono.ttf"),
|
||||
FONT("monospace.bold", "DejaVuSansMono-Bold.ttf"),
|
||||
FONT("monospace.italic", "DejaVuSansMono-Oblique.ttf"),
|
||||
FONT("monospace.bolditalic", "DejaVuSansMono-BoldOblique.ttf"),
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static void spin_lock(int volatile * lock) {
|
||||
while(__sync_lock_test_and_set(lock, 0x01)) {
|
||||
syscall_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static void spin_unlock(int volatile * lock) {
|
||||
__sync_lock_release(lock);
|
||||
}
|
||||
|
||||
void redraw_cursor() {
|
||||
draw_sprite(ctx, sprites[SPRITE_MOUSE], mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y);
|
||||
}
|
||||
|
||||
static window_t * get_window_with_process (process_windows_t * pw, wid_t wid) {
|
||||
foreach (m, pw->windows) {
|
||||
window_t * w = (window_t *)m->value;
|
||||
if (w->wid == wid) {
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_process_list () {
|
||||
process_list = list_create();
|
||||
memset(windows, 0x00000000, sizeof(window_t *) * 0x10000);
|
||||
}
|
||||
|
||||
void send_window_event (process_windows_t * pw, uint8_t event, w_window_t * packet) {
|
||||
/* Construct the header */
|
||||
wins_packet_t header;
|
||||
header.magic = WINS_MAGIC;
|
||||
header.command_type = event;
|
||||
header.packet_size = sizeof(w_window_t);
|
||||
|
||||
/* Send them */
|
||||
// XXX: we have a race condition here
|
||||
write(pw->event_pipe, &header, sizeof(wins_packet_t));
|
||||
write(pw->event_pipe, packet, sizeof(w_window_t));
|
||||
syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
|
||||
syscall_yield();
|
||||
}
|
||||
|
||||
void send_keyboard_event (process_windows_t * pw, uint8_t event, w_keyboard_t packet) {
|
||||
/* Construct the header */
|
||||
wins_packet_t header;
|
||||
header.magic = WINS_MAGIC;
|
||||
header.command_type = event;
|
||||
header.packet_size = sizeof(w_keyboard_t);
|
||||
|
||||
/* Send them */
|
||||
// XXX: we have a race condition here
|
||||
write(pw->event_pipe, &header, sizeof(wins_packet_t));
|
||||
write(pw->event_pipe, &packet, sizeof(w_keyboard_t));
|
||||
syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
|
||||
syscall_yield();
|
||||
}
|
||||
|
||||
void send_mouse_event (process_windows_t * pw, uint8_t event, w_mouse_t * packet) {
|
||||
/* Construct the header */
|
||||
wins_packet_t header;
|
||||
header.magic = WINS_MAGIC;
|
||||
header.command_type = event;
|
||||
header.packet_size = sizeof(w_mouse_t);
|
||||
|
||||
/* Send them */
|
||||
fwrite(&header, 1, sizeof(wins_packet_t), pw->event_pipe_file);
|
||||
fwrite(packet, 1, sizeof(w_mouse_t), pw->event_pipe_file);
|
||||
fflush(pw->event_pipe_file);
|
||||
//syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
|
||||
//syscall_yield();
|
||||
}
|
||||
|
||||
|
||||
int32_t min(int32_t a, int32_t b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
int32_t max(int32_t a, int32_t b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
uint8_t is_between(int32_t lo, int32_t hi, int32_t val) {
|
||||
if (val >= lo && val < hi) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
window_t * top_at(uint16_t x, uint16_t y) {
|
||||
uint32_t index_top = 0;
|
||||
window_t * window_top = NULL;
|
||||
foreach(n, process_list) {
|
||||
process_windows_t * pw = (process_windows_t *)n->value;
|
||||
foreach(node, pw->windows) {
|
||||
window_t * win = (window_t *)node->value;
|
||||
if (is_between(win->x, win->x + win->width, x) && is_between(win->y, win->y + win->height, y)) {
|
||||
if (window_top == NULL) {
|
||||
window_top = win;
|
||||
index_top = win->z;
|
||||
} else {
|
||||
if (win->z < index_top) continue;
|
||||
window_top = win;
|
||||
index_top = win->z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return window_top;
|
||||
}
|
||||
|
||||
void rebalance_windows() {
|
||||
uint32_t i = 1;
|
||||
for (; i < 0xFFF8; ++i) {
|
||||
if (!windows[i]) break;
|
||||
}
|
||||
uint32_t j = i + 1;
|
||||
for (; j < 0xFFF8; ++j) {
|
||||
if (!windows[j]) break;
|
||||
}
|
||||
if (j == i + 1) {
|
||||
return;
|
||||
} else {
|
||||
for (j = i; j < 0xFFF8; ++j) {
|
||||
windows[j] = windows[j+1];
|
||||
if (windows[j+1] == NULL) return;
|
||||
windows[j]->z = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reorder_window (window_t * window, uint16_t new_zed) {
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
int z = window->z;
|
||||
window->z = new_zed;
|
||||
|
||||
if (windows[z] == window) {
|
||||
windows[z] = NULL;
|
||||
}
|
||||
|
||||
if (new_zed == 0 || new_zed == 0xFFFF) {
|
||||
windows[new_zed] = window;
|
||||
if (z != new_zed) {
|
||||
rebalance_windows();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (windows[new_zed] != window) {
|
||||
reorder_window(windows[new_zed], new_zed + 1);
|
||||
windows[new_zed ] = window;
|
||||
}
|
||||
if (z != new_zed) {
|
||||
rebalance_windows();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void make_top(window_t * window) {
|
||||
uint16_t index = window->z;
|
||||
if (index == 0) return;
|
||||
if (index == 0xFFFF) return;
|
||||
uint16_t highest = 0;
|
||||
|
||||
foreach(n, process_list) {
|
||||
process_windows_t * pw = (process_windows_t *)n->value;
|
||||
foreach(node, pw->windows) {
|
||||
window_t * win = (window_t *)node->value;
|
||||
if (win == window) continue;
|
||||
if (win->z == 0) continue;
|
||||
if (win->z == 0xFFFF) continue;
|
||||
if (highest < win->z) highest = win->z;
|
||||
if (win == window) continue;
|
||||
if (win->z > window->z) continue;
|
||||
}
|
||||
}
|
||||
|
||||
reorder_window(window, highest+1);
|
||||
}
|
||||
|
||||
window_t * focused_window() {
|
||||
if (!focused) {
|
||||
return windows[0];
|
||||
} else {
|
||||
return focused;
|
||||
}
|
||||
}
|
||||
|
||||
void set_focused_window(window_t * n_focused) {
|
||||
if (n_focused == focused) {
|
||||
return;
|
||||
} else {
|
||||
if (focused) {
|
||||
w_window_t wwt;
|
||||
wwt.wid = focused->wid;
|
||||
wwt.left = 0;
|
||||
send_window_event(focused->owner, WE_FOCUSCHG, &wwt);
|
||||
}
|
||||
focused = n_focused;
|
||||
w_window_t wwt;
|
||||
wwt.wid = focused->wid;
|
||||
wwt.left = 1;
|
||||
send_window_event(focused->owner, WE_FOCUSCHG, &wwt);
|
||||
make_top(focused);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void set_focused_at(int x, int y) {
|
||||
window_t * n_focused = top_at(x, y);
|
||||
set_focused_window(n_focused);
|
||||
}
|
||||
|
||||
/* Internal drawing functions */
|
||||
|
||||
void window_add (window_t * window) {
|
||||
int z = window->z;
|
||||
while (windows[z]) {
|
||||
z++;
|
||||
}
|
||||
window->z = z;
|
||||
windows[z] = window;
|
||||
}
|
||||
|
||||
void unorder_window (window_t * window) {
|
||||
int z = window->z;
|
||||
if (z < 0x10000 && windows[z]) {
|
||||
windows[z] = 0;
|
||||
}
|
||||
window->z = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void blit_window(window_t * window, int32_t left, int32_t top) {
|
||||
#define TO_DERPED_OFFSET(x,y) (((x) - left) + ((y) - top) * window->width)
|
||||
uint16_t _lo_x = max(left, 0);
|
||||
uint16_t _hi_x = min(left + window->width, ctx->width);
|
||||
uint16_t _lo_y = max(top, 0);
|
||||
uint16_t _hi_y = min(top + window->height, ctx->height);
|
||||
if (window->use_alpha) {
|
||||
for (uint16_t y = _lo_y; y < _hi_y; ++y) {
|
||||
for (uint16_t x = _lo_x; x < _hi_x; ++x) {
|
||||
GFX(ctx,x,y) = alpha_blend_rgba(GFX(ctx,x,y), ((uint32_t *)window->buffer)[TO_DERPED_OFFSET(x,y)]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint16_t win_x = _lo_x - left;
|
||||
uint16_t width = (_hi_x - _lo_x) * 4;
|
||||
uint16_t win_y = _lo_y - top;
|
||||
|
||||
for (uint16_t y = _lo_y; y < _hi_y; ++y) {
|
||||
win_y = y - top;
|
||||
memcpy(&ctx->backbuffer[4 * (y * ctx->width + _lo_x)], &window->buffer[(win_y * window->width + win_x) * 4], width);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void redraw_windows() {
|
||||
for (uint32_t i = 0; i < 0x10000; ++i) {
|
||||
window_t * window = NULL;
|
||||
if (windows[i]) {
|
||||
window = windows[i];
|
||||
if (window == moving_window) {
|
||||
blit_window(moving_window, moving_window_l, moving_window_t);
|
||||
} else {
|
||||
blit_window(window, window->x, window->y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_box(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) {
|
||||
int32_t _min_x = max(x, 0);
|
||||
int32_t _min_y = max(y, 0);
|
||||
int32_t _max_x = min(x + w - 1, ctx->width - 1);
|
||||
int32_t _max_y = min(y + h - 1, ctx->height - 1);
|
||||
|
||||
draw_line(ctx, _min_x, _max_x, _min_y, _min_y, color);
|
||||
draw_line(ctx, _min_x, _max_x, _max_y, _max_y, color);
|
||||
draw_line(ctx, _min_x, _min_x, _min_y, _max_y, color);
|
||||
draw_line(ctx, _max_x, _max_x, _min_y, _max_y, color);
|
||||
}
|
||||
|
||||
void internal_free_window(window_t * window) {
|
||||
if (window == focused_window()) {
|
||||
if (window->z == 0xFFFF) {
|
||||
focused = NULL;
|
||||
return;
|
||||
}
|
||||
for (int i = window->z; i > 0; --i) {
|
||||
if (windows[i - 1]) {
|
||||
set_focused_window(windows[i - 1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_window_command (int sig) {
|
||||
foreach(n, process_list) {
|
||||
process_windows_t * pw = (process_windows_t *)n->value;
|
||||
|
||||
/* Are there any messages in this process's command pipe? */
|
||||
struct stat buf;
|
||||
fstat(pw->command_pipe, &buf);
|
||||
|
||||
int max_requests_per_cycle = 1;
|
||||
|
||||
while ((buf.st_size > 0) && (max_requests_per_cycle > 0)) {
|
||||
w_window_t wwt;
|
||||
wins_packet_t header;
|
||||
int bytes_read = read(pw->command_pipe, &header, sizeof(wins_packet_t));
|
||||
|
||||
while (header.magic != WINS_MAGIC) {
|
||||
fprintf(stderr, "[compositor] Magic is wrong from pid %d, expected 0x%x but got 0x%x [read %d bytes of %d]\n", pw->pid, WINS_MAGIC, header.magic, bytes_read, sizeof(header));
|
||||
max_requests_per_cycle--;
|
||||
goto bad_magic;
|
||||
memcpy(&header, (void *)((uintptr_t)&header + 1), (sizeof(header) - 1));
|
||||
read(pw->event_pipe, (char *)((uintptr_t)&header + sizeof(header) - 1), 1);
|
||||
}
|
||||
|
||||
max_requests_per_cycle--;
|
||||
|
||||
switch (header.command_type) {
|
||||
case WC_NEWWINDOW:
|
||||
{
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
wwt.wid = _next_wid;
|
||||
window_t * new_window = init_window(pw, _next_wid, wwt.left, wwt.top, wwt.width, wwt.height, _next_wid);
|
||||
window_add(new_window);
|
||||
_next_wid++;
|
||||
send_window_event(pw, WE_NEWWINDOW, &wwt);
|
||||
}
|
||||
break;
|
||||
|
||||
case WC_SET_ALPHA:
|
||||
{
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
window_t * window = get_window_with_process(pw, wwt.wid);
|
||||
window->use_alpha = wwt.left;
|
||||
}
|
||||
break;
|
||||
|
||||
case WC_RESIZE:
|
||||
{
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
window_t * window = get_window_with_process(pw, wwt.wid);
|
||||
resize_window_buffer(window, window->x, window->y, wwt.width, wwt.height);
|
||||
send_window_event(pw, WE_RESIZED, &wwt);
|
||||
}
|
||||
break;
|
||||
|
||||
case WC_DESTROY:
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
window_t * win = get_window_with_process(pw, wwt.wid);
|
||||
win->x = 0xFFFF;
|
||||
internal_free_window(win);
|
||||
unorder_window(win);
|
||||
/* Wait until we're done drawing */
|
||||
spin_lock(&am_drawing);
|
||||
spin_unlock(&am_drawing);
|
||||
free_window(win);
|
||||
send_window_event(pw, WE_DESTROYED, &wwt);
|
||||
break;
|
||||
|
||||
case WC_DAMAGE:
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
break;
|
||||
|
||||
case WC_REDRAW:
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
send_window_event(pw, WE_REDRAWN, &wwt);
|
||||
break;
|
||||
|
||||
case WC_REORDER:
|
||||
read(pw->command_pipe, &wwt, sizeof(w_window_t));
|
||||
reorder_window(get_window_with_process(pw, wwt.wid), wwt.left);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "[compositor] WARN: Unknown command type %d...\n", header.command_type);
|
||||
void * nullbuf = malloc(header.packet_size);
|
||||
read(pw->command_pipe, nullbuf, header.packet_size);
|
||||
free(nullbuf);
|
||||
break;
|
||||
}
|
||||
|
||||
bad_magic:
|
||||
fstat(pw->command_pipe, &buf);
|
||||
}
|
||||
}
|
||||
syscall_yield();
|
||||
}
|
||||
|
||||
/* Request page system */
|
||||
void reset_request_system () {
|
||||
_request_page->lock = 0;
|
||||
_request_page->server_done = 0;
|
||||
_request_page->client_done = 0;
|
||||
_request_page->client_pid = 0;
|
||||
_request_page->event_pipe = 0;
|
||||
_request_page->command_pipe = 0;
|
||||
|
||||
_request_page->server_pid = getpid();
|
||||
_request_page->server_width = ctx->width;
|
||||
_request_page->server_height = ctx->height;
|
||||
_request_page->server_depth = ctx->depth;
|
||||
|
||||
_request_page->magic = WINS_MAGIC;
|
||||
}
|
||||
|
||||
void init_request_system () {
|
||||
size_t size = sizeof(wins_server_global_t);
|
||||
_request_page = (wins_server_global_t *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER, &size);
|
||||
if (!_request_page) {
|
||||
fprintf(stderr, "[compositor] Could not get a shm block for its request page! Bailing...");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
reset_request_system();
|
||||
|
||||
}
|
||||
|
||||
void process_request () {
|
||||
fflush(stdout);
|
||||
if (_request_page->client_done) {
|
||||
process_windows_t * pw = malloc(sizeof(process_windows_t));
|
||||
pw->pid = _request_page->client_pid;
|
||||
pw->event_pipe = syscall_mkpipe();
|
||||
pw->event_pipe_file = fdopen(pw->event_pipe, "a");
|
||||
pw->command_pipe = syscall_mkpipe();
|
||||
pw->windows = list_create();
|
||||
|
||||
_request_page->event_pipe = syscall_share_fd(pw->event_pipe, pw->pid);
|
||||
_request_page->command_pipe = syscall_share_fd(pw->command_pipe, pw->pid);
|
||||
_request_page->client_done = 0;
|
||||
_request_page->server_done = 1;
|
||||
|
||||
list_insert(process_list, pw);
|
||||
|
||||
syscall_yield();
|
||||
}
|
||||
|
||||
if (!_request_page->lock) {
|
||||
reset_request_system();
|
||||
}
|
||||
}
|
||||
|
||||
void delete_process (process_windows_t * pw) {
|
||||
/* XXX: this is not used anywhere! We need a closing handshake signal. */
|
||||
list_destroy(pw->windows);
|
||||
list_free(pw->windows);
|
||||
free(pw->windows);
|
||||
|
||||
close(pw->command_pipe);
|
||||
close(pw->event_pipe);
|
||||
|
||||
node_t * n = list_find(process_list, pw);
|
||||
list_delete(process_list, n);
|
||||
free(n);
|
||||
free(pw);
|
||||
}
|
||||
|
||||
/* Signals */
|
||||
void * ignore(void * value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_signal_handlers () {
|
||||
#if 0
|
||||
syscall_signal(SIGWINEVENT, process_window_command); // SIGWINEVENT
|
||||
#else
|
||||
syscall_signal(SIGWINEVENT, ignore); // SIGWINEVENT
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Sprite stuff */
|
||||
void init_sprite(int i, char * filename, char * alpha) {
|
||||
sprite_t alpha_tmp;
|
||||
sprites[i] = malloc(sizeof(sprite_t));
|
||||
load_sprite(sprites[i], filename);
|
||||
if (alpha) {
|
||||
sprites[i]->alpha = 1;
|
||||
load_sprite(&alpha_tmp, alpha);
|
||||
sprites[i]->masks = alpha_tmp.bitmap;
|
||||
} else {
|
||||
sprites[i]->alpha = 0;
|
||||
}
|
||||
sprites[i]->blank = 0x0;
|
||||
}
|
||||
|
||||
void init_sprite_png(int id, char * path) {
|
||||
sprites[id] = malloc(sizeof(sprite_t));
|
||||
load_sprite_png(sprites[id], path);
|
||||
}
|
||||
|
||||
int center_x(int x) {
|
||||
return (ctx->width - x) / 2;
|
||||
}
|
||||
|
||||
int center_y(int y) {
|
||||
return (ctx->height - y) / 2;
|
||||
}
|
||||
|
||||
void display() {
|
||||
draw_fill(ctx, rgb(0,0,0));
|
||||
draw_sprite(ctx, sprites[0], center_x(sprites[0]->width), center_y(sprites[0]->height));
|
||||
flip(ctx);
|
||||
}
|
||||
|
||||
char * precacheMemFont(char * ident, char * name) {
|
||||
FILE * f = fopen(name, "r");
|
||||
size_t s = 0;
|
||||
fseek(f, 0, SEEK_END);
|
||||
s = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
size_t shm_size = s;
|
||||
char * font = (char *)syscall_shm_obtain(ident, &shm_size); //malloc(s);
|
||||
assert((shm_size >= s) && "shm_obtain returned too little memory to load a font into!");
|
||||
|
||||
fread(font, s, 1, f);
|
||||
|
||||
fclose(f);
|
||||
return font;
|
||||
}
|
||||
|
||||
void load_fonts() {
|
||||
int i = 0;
|
||||
while (fonts[i].identifier) {
|
||||
fprintf(stderr, "[compositor] Loading font %s -> %s\n", fonts[i].path, fonts[i].identifier);
|
||||
precacheMemFont(fonts[i].identifier, fonts[i].path);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void * process_requests(void * garbage) {
|
||||
int mfd = *((int *)garbage);
|
||||
|
||||
mouse_x = MOUSE_SCALE * ctx->width / 2;
|
||||
mouse_y = MOUSE_SCALE * ctx->height / 2;
|
||||
click_x = 0;
|
||||
click_y = 0;
|
||||
|
||||
uint16_t _mouse_state = 0;
|
||||
window_t * _mouse_window = NULL;
|
||||
int32_t _mouse_init_x;
|
||||
int32_t _mouse_init_y;
|
||||
int32_t _mouse_win_x;
|
||||
int32_t _mouse_win_y;
|
||||
int8_t _mouse_moved = 0;
|
||||
|
||||
int32_t _mouse_win_x_p;
|
||||
int32_t _mouse_win_y_p;
|
||||
|
||||
struct stat _stat;
|
||||
char buf[1024];
|
||||
while (1) {
|
||||
fstat(mfd, &_stat);
|
||||
while (_stat.st_size >= sizeof(mouse_device_packet_t)) {
|
||||
mouse_device_packet_t * packet = (mouse_device_packet_t *)&buf;
|
||||
int r = read(mfd, &buf, sizeof(mouse_device_packet_t));
|
||||
if (packet->magic != MOUSE_MAGIC) {
|
||||
int r = read(mfd, buf, 1);
|
||||
break;
|
||||
}
|
||||
/* Apply mouse movement */
|
||||
int l;
|
||||
l = 3;
|
||||
mouse_x += packet->x_difference * l;
|
||||
mouse_y -= packet->y_difference * l;
|
||||
if (mouse_x < 0) mouse_x = 0;
|
||||
if (mouse_y < 0) mouse_y = 0;
|
||||
if (mouse_x >= ctx->width * MOUSE_SCALE) mouse_x = (ctx->width) * MOUSE_SCALE;
|
||||
if (mouse_y >= ctx->height * MOUSE_SCALE) mouse_y = (ctx->height) * MOUSE_SCALE;
|
||||
if (_mouse_state == 0 && (packet->buttons & MOUSE_BUTTON_LEFT) && k_alt) {
|
||||
set_focused_at(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
|
||||
_mouse_window = focused_window();
|
||||
if (_mouse_window) {
|
||||
if (_mouse_window->z != 0 && _mouse_window->z != 0xFFFF) {
|
||||
_mouse_state = 1;
|
||||
_mouse_init_x = mouse_x;
|
||||
_mouse_init_y = mouse_y;
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
_mouse_win_x_p = _mouse_win_x;
|
||||
_mouse_win_y_p = _mouse_win_y;
|
||||
moving_window = _mouse_window;
|
||||
moving_window_l = _mouse_win_x_p;
|
||||
moving_window_t = _mouse_win_y_p;
|
||||
make_top(_mouse_window);
|
||||
}
|
||||
}
|
||||
} else if (_mouse_state == 0 && (packet->buttons & MOUSE_BUTTON_MIDDLE) && k_alt) {
|
||||
set_focused_at(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
|
||||
_mouse_window = focused_window();
|
||||
if (_mouse_window) {
|
||||
if (_mouse_window->z != 0 && _mouse_window->z != 0xFFFF) {
|
||||
_mouse_state = 3;
|
||||
_mouse_init_x = mouse_x;
|
||||
_mouse_init_y = mouse_y;
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
resizing_window = _mouse_window;
|
||||
resizing_window_w = _mouse_window->width;
|
||||
resizing_window_h = _mouse_window->height;
|
||||
make_top(_mouse_window);
|
||||
}
|
||||
}
|
||||
} else if (_mouse_state == 0 && (packet->buttons & MOUSE_BUTTON_LEFT) && !k_alt) {
|
||||
set_focused_at(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
|
||||
_mouse_window = focused_window();
|
||||
if (_mouse_window) {
|
||||
_mouse_state = 2; /* Dragging */
|
||||
/* In window coordinates, that's... */
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
|
||||
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
|
||||
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
|
||||
|
||||
mouse_discard = 1;
|
||||
_mouse_moved = 0;
|
||||
}
|
||||
#if 0
|
||||
_mouse_window = focused_window();
|
||||
if (_mouse_window) {
|
||||
if (_mouse_window->z == 0 || _mouse_window->z == 0xFFFF) {
|
||||
|
||||
} else {
|
||||
_mouse_state = 2;
|
||||
_mouse_init_x = mouse_x;
|
||||
_mouse_init_y = mouse_y;
|
||||
_mouse_win_x = _mouse_window->width;
|
||||
_mouse_win_y = _mouse_window->height;
|
||||
_mouse_win_x_p= _mouse_win_x;
|
||||
_mouse_win_y_p= _mouse_win_y;
|
||||
make_top(_mouse_window);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (_mouse_state == 0) {
|
||||
mouse_discard--;
|
||||
if (mouse_discard < 1) {
|
||||
mouse_discard = MOUSE_DISCARD_LEVEL;
|
||||
|
||||
w_mouse_t _packet;
|
||||
if (packet->buttons) {
|
||||
set_focused_at(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
|
||||
}
|
||||
_mouse_window = focused_window();
|
||||
_packet.wid = _mouse_window->wid;
|
||||
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
|
||||
_packet.old_x = click_x;
|
||||
_packet.old_y = click_y;
|
||||
|
||||
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
|
||||
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
|
||||
|
||||
_packet.new_x = click_x;
|
||||
_packet.new_y = click_y;
|
||||
|
||||
_packet.buttons = packet->buttons;
|
||||
_packet.command = WE_MOUSEMOVE;
|
||||
|
||||
send_mouse_event(_mouse_window->owner, WE_MOUSEMOVE, &_packet);
|
||||
}
|
||||
} else if (_mouse_state == 1) {
|
||||
if (!(packet->buttons & MOUSE_BUTTON_LEFT)) {
|
||||
_mouse_window->x = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
|
||||
_mouse_window->y = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
|
||||
moving_window = NULL;
|
||||
_mouse_state = 0;
|
||||
} else {
|
||||
_mouse_win_x_p = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
|
||||
_mouse_win_y_p = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
|
||||
moving_window_l = _mouse_win_x_p;
|
||||
moving_window_t = _mouse_win_y_p;
|
||||
}
|
||||
} else if (_mouse_state == 2) {
|
||||
if (!(packet->buttons & MOUSE_BUTTON_LEFT)) {
|
||||
/* Released */
|
||||
_mouse_state = 0;
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
|
||||
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
|
||||
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
|
||||
|
||||
if (!_mouse_moved) {
|
||||
w_mouse_t _packet;
|
||||
_packet.wid = _mouse_window->wid;
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
|
||||
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
|
||||
_packet.new_x = click_x;
|
||||
_packet.new_y = click_y;
|
||||
_packet.old_x = -1;
|
||||
_packet.old_y = -1;
|
||||
_packet.buttons = packet->buttons;
|
||||
_packet.command = WE_MOUSECLICK;
|
||||
send_mouse_event(_mouse_window->owner, WE_MOUSEMOVE, &_packet);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Still down */
|
||||
|
||||
_mouse_moved = 1;
|
||||
mouse_discard--;
|
||||
if (mouse_discard < 1) {
|
||||
mouse_discard = MOUSE_DISCARD_LEVEL;
|
||||
|
||||
w_mouse_t _packet;
|
||||
_packet.wid = _mouse_window->wid;
|
||||
|
||||
_mouse_win_x = _mouse_window->x;
|
||||
_mouse_win_y = _mouse_window->y;
|
||||
|
||||
_packet.old_x = click_x;
|
||||
_packet.old_y = click_y;
|
||||
|
||||
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
|
||||
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
|
||||
|
||||
_packet.new_x = click_x;
|
||||
_packet.new_y = click_y;
|
||||
|
||||
_packet.buttons = packet->buttons;
|
||||
_packet.command = WE_MOUSEMOVE;
|
||||
|
||||
send_mouse_event(_mouse_window->owner, WE_MOUSEMOVE, &_packet);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (_mouse_state == 3) {
|
||||
int width_diff = (mouse_x - _mouse_init_x) / MOUSE_SCALE;
|
||||
int height_diff = (mouse_y - _mouse_init_y) / MOUSE_SCALE;
|
||||
|
||||
resizing_window_w = resizing_window->width + width_diff;
|
||||
resizing_window_h = resizing_window->height + height_diff;
|
||||
if (!(packet->buttons & MOUSE_BUTTON_MIDDLE)) {
|
||||
/* Resize */
|
||||
w_window_t wwt;
|
||||
wwt.wid = resizing_window->wid;
|
||||
wwt.width = resizing_window_w;
|
||||
wwt.height = resizing_window_h;
|
||||
resize_window_buffer(resizing_window, resizing_window->x, resizing_window->y, wwt.width, wwt.height);
|
||||
send_window_event(resizing_window->owner, WE_RESIZED, &wwt);
|
||||
resizing_window = NULL;
|
||||
_mouse_state = 0;
|
||||
}
|
||||
}
|
||||
fstat(mfd, &_stat);
|
||||
}
|
||||
fstat(0, &_stat);
|
||||
if (_stat.st_size) {
|
||||
int r = read(0, buf, 1);
|
||||
if (r > 0) {
|
||||
w_keyboard_t packet;
|
||||
packet.ret = kbd_scancode(buf[0], &packet.event);
|
||||
window_t * focused = focused_window();
|
||||
if (focused) {
|
||||
packet.wid = focused->wid;
|
||||
packet.command = 0;
|
||||
packet.key = packet.ret ? packet.event.key : 0;
|
||||
send_keyboard_event(focused->owner, WE_KEYDOWN, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * redraw_thread(void * derp) {
|
||||
while (1) {
|
||||
spin_lock(&am_drawing);
|
||||
redraw_windows();
|
||||
/* Other stuff */
|
||||
redraw_cursor();
|
||||
/* Resizing window outline */
|
||||
if (resizing_window) {
|
||||
draw_box(resizing_window->x, resizing_window->y, resizing_window_w, resizing_window_h, rgb(0,128,128));
|
||||
}
|
||||
|
||||
spin_unlock(&am_drawing);
|
||||
flip(ctx);
|
||||
syscall_yield();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
/* Initialize graphics setup */
|
||||
ctx = init_graphics_fullscreen_double_buffer();
|
||||
|
||||
/* Initialize the client request system */
|
||||
init_request_system();
|
||||
|
||||
/* Initialize process list */
|
||||
init_process_list();
|
||||
|
||||
/* Initialize signal handlers */
|
||||
init_signal_handlers();
|
||||
|
||||
/* Load sprites */
|
||||
init_sprite_png(0, "/usr/share/logo_login.png");
|
||||
display();
|
||||
|
||||
/* Precache shared memory fonts */
|
||||
load_fonts();
|
||||
|
||||
/* load the mouse cursor */
|
||||
init_sprite(SPRITE_MOUSE, "/usr/share/arrow.bmp","/usr/share/arrow_alpha.bmp");
|
||||
|
||||
/* Grab the mouse */
|
||||
int mfd = syscall_mousedevice();
|
||||
pthread_t input_thread;
|
||||
pthread_create(&input_thread, NULL, process_requests, (void *)&mfd);
|
||||
|
||||
pthread_t redraw_everything_thread;
|
||||
pthread_create(&redraw_everything_thread, NULL, redraw_thread, NULL);
|
||||
|
||||
setenv("DISPLAY", WINS_SERVER_IDENTIFIER, 1);
|
||||
|
||||
if (!fork()) {
|
||||
syscall_system_function(5,0);
|
||||
#if SINGLE_USER_MODE
|
||||
#ifdef FORCE_UID
|
||||
syscall_setuid(FORCE_UID);
|
||||
#endif
|
||||
char * args[] = {"/bin/gsession", NULL};
|
||||
#else
|
||||
char * args[] = {"/bin/glogin", NULL};
|
||||
#endif
|
||||
execvp(args[0], args);
|
||||
}
|
||||
|
||||
/* Sit in a run loop */
|
||||
while (1) {
|
||||
process_request();
|
||||
process_window_command(0);
|
||||
syscall_yield();
|
||||
}
|
||||
|
||||
// XXX: Better have SIGINT/SIGSTOP handlers
|
||||
return 0;
|
||||
}
|
@ -24,9 +24,9 @@
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
int mk_wcwidth_cjk(wchar_t ucs);
|
||||
|
||||
#include "lib/utf8decode.h"
|
||||
#include "lib/wcwidth.h"
|
||||
|
||||
#define BLOCK_SIZE 256
|
||||
#define ENTER_KEY '\n'
|
@ -29,8 +29,8 @@
|
||||
DEFN_SYSCALL2(nanosleep, 46, unsigned long, unsigned long);
|
||||
|
||||
#include <wchar.h>
|
||||
int mk_wcwidth_cjk(wchar_t ucs);
|
||||
|
||||
#include "lib/wcwidth.h"
|
||||
#include "lib/utf8decode.h"
|
||||
#include "../kernel/include/mouse.h"
|
||||
|
6
userspace/lib/wcwidth.h
Normal file
6
userspace/lib/wcwidth.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef MK_WCWIDTH
|
||||
#define MK_WCWIDTH
|
||||
|
||||
int mk_wcwidth_cjk(wchar_t ucs);
|
||||
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* shm-client - client program to demonstrate shared memory.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <syscall.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SHMSZ 27
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int shmid;
|
||||
volatile char *shm;
|
||||
volatile char *s;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
char * key = argv[1];
|
||||
|
||||
/*
|
||||
* Attach the segment to our data space.
|
||||
*/
|
||||
size_t size = SHMSZ;
|
||||
malloc(9 * 0x1000); // Make our heap a bit different from the server
|
||||
if ((shm = (char *)syscall_shm_obtain(key, &size)) == (char *) NULL) {
|
||||
printf("Client: syscall_shm_mount returned NULL!\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Client: mounted to 0x%x\n", shm);
|
||||
|
||||
/*
|
||||
* Now read what the server put in the memory.
|
||||
*/
|
||||
while (*shm != 'a');
|
||||
for (s = shm; *s != '\0'; s++)
|
||||
printf("%c", *s);
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* Finally, change the first character of the
|
||||
* segment to '*', indicating we have read
|
||||
* the segment.
|
||||
*/
|
||||
*shm = '*';
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* shm-server - client program to demonstrate shared memory.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <syscall.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SHMSZ 27
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
char c;
|
||||
volatile char *shm;
|
||||
volatile char *s;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
char * key = argv[1];
|
||||
|
||||
/*
|
||||
* Attach to the shared memory chunk
|
||||
*/
|
||||
size_t size = SHMSZ;
|
||||
if ((shm = (char *)syscall_shm_obtain(key, &size)) == (char *) NULL) {
|
||||
return 1;
|
||||
}
|
||||
printf("Server: mounted to 0x%x\n", shm);
|
||||
|
||||
/*
|
||||
* Now put some things into the memory for the
|
||||
* other process to read.
|
||||
*/
|
||||
s = shm;
|
||||
|
||||
for (c = 'a'; c <= 'z'; c++)
|
||||
*s++ = c;
|
||||
*s = '\0';
|
||||
|
||||
|
||||
/*
|
||||
* Finally, we wait until the other process
|
||||
* changes the first character of our memory
|
||||
* to '*', indicating that it has read what
|
||||
* we put there.
|
||||
*/
|
||||
while (*shm != '*') {}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* shmcrash
|
||||
* Like shmcrash2, except it's not #2!
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main_server(volatile char *shm);
|
||||
int main_client(volatile char *shm);
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("(This should fork and the child process (but not the parent) should segfault)\n");
|
||||
|
||||
size_t size = 27;
|
||||
volatile char * shm = (char *)syscall_shm_obtain(argv[1], &size);
|
||||
if (shm == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t f = fork();
|
||||
if (getpid() != pid) {
|
||||
// Child: client
|
||||
return main_client(shm);
|
||||
} else {
|
||||
// Parent: server
|
||||
return main_server(shm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main_server(volatile char *shm) {
|
||||
char c;
|
||||
volatile char *s;
|
||||
|
||||
/*
|
||||
* Now put some things into the memory for the
|
||||
* other process to read.
|
||||
*/
|
||||
s = shm;
|
||||
|
||||
for (c = 'a'; c <= 'z'; c++)
|
||||
*s++ = c;
|
||||
*s = '\0';
|
||||
|
||||
|
||||
/*
|
||||
* Finally, we wait until the other process
|
||||
* changes the first character of our memory
|
||||
* to '*', indicating that it has read what
|
||||
* we put there.
|
||||
*/
|
||||
while (*shm != '*') {}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_client(volatile char *shm) {
|
||||
int shmid;
|
||||
volatile char *s;
|
||||
|
||||
/*
|
||||
* Now read what the server put in the memory.
|
||||
*/
|
||||
while (*shm != 'a');
|
||||
for (s = shm; *s != '\0'; s++)
|
||||
printf("%c", *s);
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* Finally, change the first character of the
|
||||
* segment to '*', indicating we have read
|
||||
* the segment.
|
||||
*/
|
||||
*shm = '*';
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* shmcrash2
|
||||
*
|
||||
* crashes!
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("(this should not crash; but the kernel should free the shm block)\n");
|
||||
|
||||
size_t size = 0x1000;
|
||||
volatile char * shm = (char *)syscall_shm_obtain(argv[1], &size);
|
||||
if (shm == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * args[] = {"/bin/echo", "exec'd to echo\n", NULL};
|
||||
execvp(args[0], args);
|
||||
|
||||
return 5;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* shmtest
|
||||
* It's an shmtest.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: expected argument\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
char * tokens[] = { NULL, argv[1], NULL };
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t f = fork();
|
||||
if (getpid() != pid) {
|
||||
// Child: client
|
||||
tokens[0] = "/bin/shm_client";
|
||||
execvp(tokens[0], tokens);
|
||||
return 3;
|
||||
} else {
|
||||
// Parent: server
|
||||
tokens[0] = "/bin/shm_server";
|
||||
execvp(tokens[0], tokens);
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* shmtest2
|
||||
* It's a test app. For shm.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define KEY "shm_test3.mem"
|
||||
#define MAGIC 111
|
||||
|
||||
int client_proc(uint32_t size) {
|
||||
volatile unsigned char * mem = (volatile unsigned char *)syscall_shm_obtain(KEY, &size);
|
||||
|
||||
while (mem[0] != MAGIC) {}
|
||||
mem[0] = (uint8_t)(MAGIC + 1);
|
||||
|
||||
for (uint32_t i = 1; i < size; i++) {
|
||||
if (mem[i] != (unsigned char)i) {
|
||||
printf("Verification at 0x%x (i=%d) failed; expected=%d got=%d\n", &mem[i], i, (uint8_t)i, mem[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Client: verification passed. Exiting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int server_proc(uint32_t size) {
|
||||
volatile unsigned char * mem = (volatile unsigned char *)syscall_shm_obtain(KEY, &size);
|
||||
|
||||
for (uint32_t i = 1; i < size; i++) {
|
||||
mem[i] = (unsigned char)i;
|
||||
}
|
||||
mem[0] = MAGIC;
|
||||
printf("Server: Written memory space.\n");
|
||||
|
||||
while (mem[0] == MAGIC) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
if (argc < 2) {
|
||||
printf("usage: %s [size]\n", argv[0]);
|
||||
}
|
||||
|
||||
int size = atoi(argv[1]);
|
||||
|
||||
if (!fork()) {
|
||||
return server_proc(size);
|
||||
} else {
|
||||
return client_proc(size);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user