64kiB kernel area, ps/2 mouse support, signed decimals in knob format
This commit is contained in:
		
							parent
							
								
									43693f88c7
								
							
						
					
					
						commit
						81df4702c4
					
				
					 16 changed files with 304 additions and 83 deletions
				
			
		| 
						 | 
				
			
			@ -17,9 +17,10 @@
 | 
			
		|||
0x0000.5000 - 0x0000.5fff   (4k): kernel page directory
 | 
			
		||||
 | 
			
		||||
0x0001.0000 - 0x0001.ffff  (64k): BIOS memory map
 | 
			
		||||
 | 
			
		||||
0x0003.0000 - 0x0003.7fff  (32k): kernel text, data, rodata
 | 
			
		||||
0x0003.8000 - 0x0003.ffff  (32k): kernel stack
 | 
			
		||||
0x0002.0000 - 0x0002.0fff   (4k): kernel stack guard
 | 
			
		||||
0x0002.1000 - 0x0002.efff  (56k): kernel stack
 | 
			
		||||
0x0002.f000 - 0x0002.ffff   (4k): kernel stack guard
 | 
			
		||||
0x0003.0000 - 0x0003.ffff  (64k): kernel text, data, rodata
 | 
			
		||||
0x0004.0000 - 0x0005.ffff (128k): pagemap
 | 
			
		||||
0x0006.0000 - 0x0007.ffff (128k): shared kernel page tables
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,6 @@ see table 1
 | 
			
		|||
 | 
			
		||||
file system calls have units of bytes unless otherwise specified.
 | 
			
		||||
functions returning handles or pointers use 0 to indicate error.
 | 
			
		||||
see keys.txt for the return type of the "get key" system call.
 | 
			
		||||
the edx register of "start task" is a pointer to a null-terminated string.
 | 
			
		||||
  a pointer to a readonly copy of this string is put into the new task's edx.
 | 
			
		||||
  the esi register is passed through directly, and is meant to be a task handle.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,6 @@ the top 24 bits indicate several flags. these are seen in table 2, where bit 0
 | 
			
		|||
is the lowest bit of the second lowest byte of the keycode, and bit 23 is the
 | 
			
		||||
highest bit of the highest byte of the keycode.
 | 
			
		||||
 | 
			
		||||
the "get key" system call returns 0 if there is not a key available. it is
 | 
			
		||||
recommended to make the system call and, if it returns 0, yield to the scheduler
 | 
			
		||||
and then loop back to making the system call. this way your task does not block
 | 
			
		||||
the cpu while waiting for keyboard input. see the "get_key_char" function in
 | 
			
		||||
user.c of the "knob" library for an example of this.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
table 1:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +44,7 @@ table 1:
 | 
			
		|||
 0xaa | F11
 | 
			
		||||
 0xab | F12
 | 
			
		||||
 0xac | unassigned
 | 
			
		||||
 .... | unassigned
 | 
			
		||||
 ...  | unassigned
 | 
			
		||||
 0xaf | unassigned
 | 
			
		||||
 0xb0 | numpad 0
 | 
			
		||||
 0xb1 | numpad 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
bin/mkpopup Press Win+Space to open a terminal.\nPress Win+Arrow Key to move a window around.\nPress Win+Page Up/Down to shuffle windows.\nTry typing 'dirlist bin' into a terminal!\nPress Escape to close this window.
 | 
			
		||||
bin/mkpopup Press Win+Space to open a terminal with a shell.\nPress Win+Arrow Key to move a window around.\nClick on a window to focus it.\nPress escape to close this window.\nTo list all of the installed programs,\n  type "dirlist bin" into a shell.
 | 
			
		||||
							
								
								
									
										8
									
								
								makefile
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ out/disk.vdi: out/disk.img
 | 
			
		|||
 | 
			
		||||
out/disk.img: out/kernel.bin out/boot.bin out/fs
 | 
			
		||||
	mkdir -p obj
 | 
			
		||||
	mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 65 -s 1 -S 512 obj/shadow.img 8192
 | 
			
		||||
	mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 129 -s 1 -S 512 obj/shadow.img 8192
 | 
			
		||||
	echo -n -e '\xeb\x3c' > obj/jmp.bin
 | 
			
		||||
	dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc
 | 
			
		||||
	dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ out/fs/bin/%: obj/%.elf
 | 
			
		|||
out/fs: out/fs/bin/init     out/fs/bin/highway out/fs/bin/meminfo \
 | 
			
		||||
        out/fs/bin/terminal out/fs/bin/hello   out/fs/bin/mkpopup \
 | 
			
		||||
        out/fs/bin/dirlist  out/fs/bin/ttt     out/fs/bin/time    \
 | 
			
		||||
        out/fs/bin/filetest
 | 
			
		||||
        out/fs/bin/filetest out/fs/bin/mdemo
 | 
			
		||||
	touch out/fs
 | 
			
		||||
	cp -r fs-skel/* out/fs/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -137,3 +137,7 @@ obj/time.elf: obj/time/time.o obj/libterm.so obj/knob.so \
 | 
			
		|||
obj/filetest.elf: obj/filetest/filetest.o obj/libterm.so obj/knob.so \
 | 
			
		||||
                  obj/c.rto
 | 
			
		||||
	ld -T src/user/runtimes/c/elf.ld $^ -o $@
 | 
			
		||||
 | 
			
		||||
obj/mdemo.elf: obj/mdemo/main.o obj/popups.so obj/libfont.so \
 | 
			
		||||
               obj/knob.so      obj/c.rto
 | 
			
		||||
	ld -T src/user/runtimes/c/elf.ld $^ -o $@
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
bits 16
 | 
			
		||||
org 0x7c3e
 | 
			
		||||
 | 
			
		||||
kernel_sectors equ 64
 | 
			
		||||
kernel_sectors equ 128
 | 
			
		||||
kernel_segment equ 0x3000
 | 
			
		||||
 | 
			
		||||
support_flags equ 0x4000
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ pmode:
 | 
			
		|||
  mov ds, ax
 | 
			
		||||
  mov es, ax
 | 
			
		||||
  mov ss, ax
 | 
			
		||||
  mov esp, 0x00040000
 | 
			
		||||
  mov esp, 0x0002f000
 | 
			
		||||
 | 
			
		||||
  xor ebp, ebp
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -219,6 +219,7 @@ extern isr_t quit_isr;
 | 
			
		|||
extern isr_t yield_isr;
 | 
			
		||||
 | 
			
		||||
extern isr_t kbd_isr;
 | 
			
		||||
extern isr_t mouse_isr;
 | 
			
		||||
 | 
			
		||||
extern isr_t udf_isr;
 | 
			
		||||
extern isr_t dfa_isr;
 | 
			
		||||
| 
						 | 
				
			
			@ -325,6 +326,7 @@ void init_idt() {
 | 
			
		|||
  register_int(0x39, &yield_isr, 3);
 | 
			
		||||
 | 
			
		||||
  register_int(0x21, &kbd_isr, 0);
 | 
			
		||||
  register_int(0x2c, &mouse_isr, 0);
 | 
			
		||||
 | 
			
		||||
  register_int(0x08, &udf_isr, 0);
 | 
			
		||||
  register_int(0x08, &dfa_isr, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -346,8 +348,8 @@ void init_idt() {
 | 
			
		|||
  outb(PIC_MDATA, 0x01);
 | 
			
		||||
  outb(PIC_SDATA, 0x01);
 | 
			
		||||
 | 
			
		||||
  outb(PIC_MDATA, 0xfd);
 | 
			
		||||
  outb(PIC_SDATA, 0xff);
 | 
			
		||||
  outb(PIC_MDATA, 0xf9);
 | 
			
		||||
  outb(PIC_SDATA, 0xef);
 | 
			
		||||
 | 
			
		||||
  asm volatile (
 | 
			
		||||
    "lidt %0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ global quit_isr
 | 
			
		|||
global yield_isr
 | 
			
		||||
global _start_user_mode
 | 
			
		||||
global kbd_isr
 | 
			
		||||
global mouse_isr
 | 
			
		||||
 | 
			
		||||
global udf_isr
 | 
			
		||||
global dfa_isr
 | 
			
		||||
| 
						 | 
				
			
			@ -133,6 +134,22 @@ _start_user_mode:
 | 
			
		|||
  sub esp, 4
 | 
			
		||||
  jmp yield_isr.return_to_task
 | 
			
		||||
 | 
			
		||||
mouse_isr:
 | 
			
		||||
  push eax
 | 
			
		||||
  push ecx
 | 
			
		||||
  push edx
 | 
			
		||||
 | 
			
		||||
  call on_kbd_isr
 | 
			
		||||
 | 
			
		||||
  mov al, 0x20
 | 
			
		||||
  out 0x00a0, al
 | 
			
		||||
  out 0x0020, al
 | 
			
		||||
 | 
			
		||||
  pop edx
 | 
			
		||||
  pop ecx
 | 
			
		||||
  pop eax
 | 
			
		||||
  iret
 | 
			
		||||
 | 
			
		||||
kbd_isr:
 | 
			
		||||
  push eax
 | 
			
		||||
  push ecx
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,18 +21,38 @@ enum {
 | 
			
		|||
enum {
 | 
			
		||||
  PS2C_READ_CONFIG  = 0x20,
 | 
			
		||||
  PS2C_WRITE_CONFIG = 0x60,
 | 
			
		||||
  PS2C_AUX_ENABLE   = 0xa8,
 | 
			
		||||
  PS2C_DISABLE      = 0xad,
 | 
			
		||||
  PS2C_ENABLE       = 0xae
 | 
			
		||||
  PS2C_ENABLE       = 0xae,
 | 
			
		||||
  PS2C_SEND_AUX     = 0xd4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PS2S_CODE_READY = 0x01
 | 
			
		||||
  PS2S_CODE_READY = 0x01,
 | 
			
		||||
  PS2S_DONT_SEND  = 0x02,
 | 
			
		||||
  PS2S_FROM_MOUSE = 0x20
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PS2G_KBD_IRQ     = 0x01,
 | 
			
		||||
  PS2G_MOUSE_IRQ   = 0x02,
 | 
			
		||||
  PS2G_KBD_OFF     = 0x10,
 | 
			
		||||
  PS2G_MOUSE_OFF   = 0x20,
 | 
			
		||||
  PS2G_XT_COMPAT   = 0x40
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  MFB_BUTTON_ONE = 0x01,
 | 
			
		||||
  MFB_BUTTON_TWO = 0x02,
 | 
			
		||||
  MFB_BUTTON_MID = 0x04,
 | 
			
		||||
  MFB_X_SIGN     = 0x10,
 | 
			
		||||
  MFB_Y_SIGN     = 0x20
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  MC_ENABLE_REPORT = 0xf4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t n_scantabs;
 | 
			
		||||
 | 
			
		||||
static struct scantab_info {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +75,16 @@ void init_kbd() {
 | 
			
		|||
  outb(PS2_CMD, PS2C_READ_CONFIG);
 | 
			
		||||
  uint8_t config = inb(PS2_DATA);
 | 
			
		||||
  outb(PS2_CMD, PS2C_WRITE_CONFIG);
 | 
			
		||||
  outb(PS2_DATA, config | PS2G_XT_COMPAT);
 | 
			
		||||
  outb(PS2_DATA, (config | PS2G_XT_COMPAT | PS2G_MOUSE_IRQ | PS2G_KBD_IRQ) & ~(PS2G_MOUSE_OFF | PS2G_KBD_OFF));
 | 
			
		||||
 | 
			
		||||
  outb(PS2_CMD, PS2C_SEND_AUX);
 | 
			
		||||
  while (inb(PS2_CMD) & PS2S_DONT_SEND)
 | 
			
		||||
    ;
 | 
			
		||||
  outb(PS2_DATA, MC_ENABLE_REPORT);
 | 
			
		||||
  while (!(inb(PS2_CMD) & PS2S_CODE_READY))
 | 
			
		||||
    ;
 | 
			
		||||
  if (inb(PS2_DATA) != 0xfa)
 | 
			
		||||
    PANIC("didn't get ACK after enabling mouse reporting");
 | 
			
		||||
 | 
			
		||||
  uint32_t layout_len;
 | 
			
		||||
  if (!try_get_sz_setting("kbd-layout", scantab_path + SCANTAB_DIR_LEN, LAYOUT_NAME_MAX_LEN, &layout_len))
 | 
			
		||||
| 
						 | 
				
			
			@ -107,11 +136,54 @@ static inline uint8_t get_next_code_byte() {
 | 
			
		|||
  return cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint8_t get_wait() {
 | 
			
		||||
  for (uint32_t i = 0; i < 1000000; ++i)
 | 
			
		||||
    ;
 | 
			
		||||
  return inb(PS2_DATA);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum key_modifiers_t keymods = 0;
 | 
			
		||||
 | 
			
		||||
bool last_mouse_one = false;
 | 
			
		||||
bool last_mouse_two = false;
 | 
			
		||||
bool last_mouse_mid = false;
 | 
			
		||||
 | 
			
		||||
enum kbd_isr_result on_kbd_isr() {
 | 
			
		||||
//logf(LOG_INFO, "on_kbd_isr()");
 | 
			
		||||
  while (inb(PS2_CMD) & PS2S_CODE_READY) {
 | 
			
		||||
  uint8_t code;
 | 
			
		||||
  while ((code = inb(PS2_CMD)) & PS2S_CODE_READY) {
 | 
			
		||||
    if (code & PS2S_FROM_MOUSE) {
 | 
			
		||||
      const uint8_t first = get_wait();
 | 
			
		||||
      const uint8_t x = get_wait();
 | 
			
		||||
      const uint8_t y = get_wait();
 | 
			
		||||
 | 
			
		||||
      if (x || y || (first & (MFB_X_SIGN | MFB_Y_SIGN)))
 | 
			
		||||
        move_mouse_by((first & MFB_Y_SIGN) ? 256 - y : -y,
 | 
			
		||||
                      (first & MFB_X_SIGN) ? x - 256 : x);
 | 
			
		||||
 | 
			
		||||
      const bool mouse_one = first & MFB_BUTTON_ONE;
 | 
			
		||||
      const bool mouse_two = first & MFB_BUTTON_TWO;
 | 
			
		||||
      const bool mouse_mid = first & MFB_BUTTON_MID;
 | 
			
		||||
 | 
			
		||||
      if (mouse_one && !last_mouse_one)
 | 
			
		||||
        mouse_button(LEFT, false);
 | 
			
		||||
      if (mouse_two && !last_mouse_two)
 | 
			
		||||
        mouse_button(RIGHT, false);
 | 
			
		||||
      if (mouse_mid && !last_mouse_mid)
 | 
			
		||||
        mouse_button(MIDDLE, false);
 | 
			
		||||
 | 
			
		||||
      if (!mouse_one && last_mouse_one)
 | 
			
		||||
        mouse_button(LEFT, true);
 | 
			
		||||
      if (!mouse_two && last_mouse_two)
 | 
			
		||||
        mouse_button(RIGHT, true);
 | 
			
		||||
      if (!mouse_mid && last_mouse_mid)
 | 
			
		||||
        mouse_button(MIDDLE, true);
 | 
			
		||||
 | 
			
		||||
      last_mouse_one = mouse_one;
 | 
			
		||||
      last_mouse_two = mouse_two;
 | 
			
		||||
      last_mouse_mid = mouse_mid;
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    last_code_byte = 0;
 | 
			
		||||
    uint8_t code[256];
 | 
			
		||||
    uint8_t code_i = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,11 +115,15 @@ void init_paging() {
 | 
			
		|||
 | 
			
		||||
  for (uint32_t i = 0; i < 1048576; ++i)
 | 
			
		||||
    KPAGE_TABLE_0[i] = (i * 4096) | PE_WRITABLE | PE_PRESENT;
 | 
			
		||||
  KPAGE_TABLE_0[0x00020] &= ~PE_PRESENT;
 | 
			
		||||
  KPAGE_TABLE_0[0x0002f] &= ~PE_PRESENT;
 | 
			
		||||
  for (uint16_t i = 0; i < 1024; ++i)
 | 
			
		||||
    KPAGE_DIR[i] = (uint32_t)(KPAGE_TABLE_0 + i * 1024) | PE_WRITABLE | PE_PRESENT;
 | 
			
		||||
 | 
			
		||||
  for (uint16_t i = 0; i < KERNEL_END / 4096; ++i)
 | 
			
		||||
    kmap[i] = (i * 4096) | PE_USER | PE_PRESENT;
 | 
			
		||||
  kmap[0x00020] &= ~PE_PRESENT;
 | 
			
		||||
  kmap[0x0002f] &= ~PE_PRESENT;
 | 
			
		||||
 | 
			
		||||
  asm volatile (
 | 
			
		||||
    "mov $0x00005000, %%eax\n"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,11 +62,11 @@ uint32_t new_task(struct task_state state) {
 | 
			
		|||
 | 
			
		||||
static void tmp_halt() {
 | 
			
		||||
//logf(LOG_INFO, "scheduler halting");
 | 
			
		||||
  TSS->esp0 = 0x0003c000;
 | 
			
		||||
  TSS->esp0 = 0x00028000;
 | 
			
		||||
  asm("sti\n"
 | 
			
		||||
      "hlt\n"
 | 
			
		||||
      "cli");
 | 
			
		||||
  TSS->esp0 = 0x00040000;
 | 
			
		||||
  TSS->esp0 = 0x0002f000;
 | 
			
		||||
//logf(LOG_INFO, "scheduler resumed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +121,7 @@ void init_tasks() {
 | 
			
		|||
    ipc_pipes[i].buffer = 0;
 | 
			
		||||
 | 
			
		||||
  TSS->ss0 = 0x18;
 | 
			
		||||
  TSS->esp0 = 0x00040000;
 | 
			
		||||
  TSS->esp0 = 0x0002f000;
 | 
			
		||||
//TSS->cs = 0x13;
 | 
			
		||||
//TSS->ds = 0x1b;
 | 
			
		||||
//TSS->ss = 0x1b;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,6 +71,49 @@ static void load_mode_params() {
 | 
			
		|||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void blit_pixel(uint32_t *into, struct pixel from) {
 | 
			
		||||
  *into &= pix_clear_mask;
 | 
			
		||||
  *into |= (from.r >> (8 - VBE_MODE_INFO->red_len))   << VBE_MODE_INFO->red_off;
 | 
			
		||||
  *into |= (from.g >> (8 - VBE_MODE_INFO->green_len)) << VBE_MODE_INFO->green_off;
 | 
			
		||||
  *into |= (from.b >> (8 - VBE_MODE_INFO->blue_len))  << VBE_MODE_INFO->blue_off;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint16_t mouse_y;
 | 
			
		||||
static uint16_t mouse_x;
 | 
			
		||||
 | 
			
		||||
#define MOUSE_WIDTH 8
 | 
			
		||||
#define MOUSE_HEIGHT 8
 | 
			
		||||
 | 
			
		||||
#define B {.r = 0, .g = 0, .b = 0, .pad = 0}
 | 
			
		||||
#define W {.r = 255, .g = 255, .b = 255, .pad = 0}
 | 
			
		||||
#define T {.pad = 1}
 | 
			
		||||
 | 
			
		||||
static const struct pixel mouse_image[] = {
 | 
			
		||||
  W, W, W, W, W, W, T, T,
 | 
			
		||||
  W, B, B, B, W, T, T, T,
 | 
			
		||||
  W, B, B, B, W, W, T, T,
 | 
			
		||||
  W, B, B, B, B, W, W, T,
 | 
			
		||||
  W, W, W, B, B, B, W, T,
 | 
			
		||||
  W, T, W, W, B, B, B, W,
 | 
			
		||||
  T, T, T, W, W, B, W, W,
 | 
			
		||||
  T, T, T, T, W, W, W, T
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void blit_mouse() {
 | 
			
		||||
  uint16_t y_max = mouse_y + MOUSE_HEIGHT > VBE_MODE_INFO->height ? VBE_MODE_INFO->height - mouse_y : MOUSE_HEIGHT;
 | 
			
		||||
  uint16_t x_max = mouse_x + MOUSE_WIDTH  > VBE_MODE_INFO->width  ? VBE_MODE_INFO->width  - mouse_x : MOUSE_WIDTH;
 | 
			
		||||
  void *row = VBE_MODE_INFO->frame_buf + mouse_y * VBE_MODE_INFO->pitch + mouse_x * (VBE_MODE_INFO->bpp / 8);
 | 
			
		||||
  for (uint16_t y = 0; y < y_max; ++y) {
 | 
			
		||||
    uint32_t *out_pix = row;
 | 
			
		||||
    for (uint16_t x = 0; x < x_max; ++x) {
 | 
			
		||||
      if (!mouse_image[y * MOUSE_WIDTH + x].pad)
 | 
			
		||||
        blit_pixel(out_pix, mouse_image[y * MOUSE_WIDTH + x]);
 | 
			
		||||
      out_pix = (uint32_t *)((void *)out_pix + VBE_MODE_INFO->bpp / 8);
 | 
			
		||||
    }
 | 
			
		||||
    row += VBE_MODE_INFO->pitch;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blit(uint16_t x_min, uint16_t x_max, uint16_t y_min, uint16_t y_max) {
 | 
			
		||||
  void *row = VBE_MODE_INFO->frame_buf + y_min * VBE_MODE_INFO->pitch + x_min * (VBE_MODE_INFO->bpp / 8);
 | 
			
		||||
  const struct super_pixel *from_row = buffer + y_min * VBE_MODE_INFO->width + x_min;
 | 
			
		||||
| 
						 | 
				
			
			@ -78,16 +121,17 @@ static void blit(uint16_t x_min, uint16_t x_max, uint16_t y_min, uint16_t y_max)
 | 
			
		|||
    uint32_t *out_pix = row;
 | 
			
		||||
    const struct super_pixel *from = from_row;
 | 
			
		||||
    for (uint16_t x = x_min; x < x_max; ++x) {
 | 
			
		||||
      *out_pix &= pix_clear_mask;
 | 
			
		||||
      *out_pix |= (from->p.r >> (8 - VBE_MODE_INFO->red_len))   << VBE_MODE_INFO->red_off;
 | 
			
		||||
      *out_pix |= (from->p.g >> (8 - VBE_MODE_INFO->green_len)) << VBE_MODE_INFO->green_off;
 | 
			
		||||
      *out_pix |= (from->p.b >> (8 - VBE_MODE_INFO->blue_len))  << VBE_MODE_INFO->blue_off;
 | 
			
		||||
      blit_pixel(out_pix, from->p);
 | 
			
		||||
      out_pix = (uint32_t *)((void *)out_pix + VBE_MODE_INFO->bpp / 8);
 | 
			
		||||
      ++from;
 | 
			
		||||
    }
 | 
			
		||||
    row += VBE_MODE_INFO->pitch;
 | 
			
		||||
    from_row += VBE_MODE_INFO->width;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((y_min < mouse_y) && (y_max > mouse_y) &&
 | 
			
		||||
      (x_min < mouse_x) && (x_max > mouse_x))
 | 
			
		||||
    blit_mouse();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define POWER_OFF_MESSAGE_PITCH 45
 | 
			
		||||
| 
						 | 
				
			
			@ -343,8 +387,6 @@ static void send_action(struct window *w, struct window_action packet) {
 | 
			
		|||
#define RUN_COMMAND_FILE "sys/winspace.rc"
 | 
			
		||||
 | 
			
		||||
enum wm_action {
 | 
			
		||||
  WM_SHUFFLE_UP,
 | 
			
		||||
  WM_SHUFFLE_DOWN,
 | 
			
		||||
  WM_MOVE_LEFT,
 | 
			
		||||
  WM_MOVE_RIGHT,
 | 
			
		||||
  WM_MOVE_UP,
 | 
			
		||||
| 
						 | 
				
			
			@ -355,8 +397,6 @@ enum wm_action {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
static struct key_packet keybinds[] = {
 | 
			
		||||
  {.key_id = KEY_PAGE_DOWN,   .modifiers = WINS},
 | 
			
		||||
  {.key_id = KEY_PAGE_UP,     .modifiers = WINS},
 | 
			
		||||
  {.key_id = KEY_LEFT_ARROW,  .modifiers = WINS},
 | 
			
		||||
  {.key_id = KEY_RIGHT_ARROW, .modifiers = WINS},
 | 
			
		||||
  {.key_id = KEY_UP_ARROW,    .modifiers = WINS},
 | 
			
		||||
| 
						 | 
				
			
			@ -393,6 +433,10 @@ void init_win() {
 | 
			
		|||
  paint_bg();
 | 
			
		||||
  blit(0, VBE_MODE_INFO->width, 0, VBE_MODE_INFO->height);
 | 
			
		||||
 | 
			
		||||
  mouse_x = (VBE_MODE_INFO->width  - MOUSE_WIDTH)  / 2;
 | 
			
		||||
  mouse_y = (VBE_MODE_INFO->height - MOUSE_HEIGHT) / 2;
 | 
			
		||||
  blit_mouse();
 | 
			
		||||
 | 
			
		||||
  const file_id_t fid = drives->get_file(drives, RUN_COMMAND_FILE);
 | 
			
		||||
  if (!fid)
 | 
			
		||||
    PANIC("Couldn't open " RUN_COMMAND_FILE ".");
 | 
			
		||||
| 
						 | 
				
			
			@ -425,34 +469,7 @@ void on_action(struct window_action packet) {
 | 
			
		|||
    for (uint8_t i = 0; i < N_WM_ACTIONS; ++i)
 | 
			
		||||
      if (fuzzy_key_match(keybinds[i], packet.as_key)) {
 | 
			
		||||
        switch_to_kernel_cr3();
 | 
			
		||||
        struct window *old_top, *old_bottom;
 | 
			
		||||
        switch (i) {
 | 
			
		||||
        case WM_SHUFFLE_UP:
 | 
			
		||||
          if (!top_window || !top_window->below)
 | 
			
		||||
            break;
 | 
			
		||||
          old_top = top_window;
 | 
			
		||||
          old_bottom = bottom_window;
 | 
			
		||||
          top_window = old_top->below;
 | 
			
		||||
          top_window->above = 0;
 | 
			
		||||
          old_top->below = 0;
 | 
			
		||||
          old_top->above = old_bottom;
 | 
			
		||||
          old_bottom->below = old_top;
 | 
			
		||||
          bottom_window = old_top;
 | 
			
		||||
          paint_and_above(bottom_window->above);
 | 
			
		||||
          break;
 | 
			
		||||
        case WM_SHUFFLE_DOWN:
 | 
			
		||||
          if (!top_window || !top_window->below)
 | 
			
		||||
            break;
 | 
			
		||||
          old_top = top_window;
 | 
			
		||||
          old_bottom = bottom_window;
 | 
			
		||||
          bottom_window = old_bottom->above;
 | 
			
		||||
          bottom_window->below = 0;
 | 
			
		||||
          old_bottom->above = 0;
 | 
			
		||||
          old_bottom->below = old_top;
 | 
			
		||||
          old_top->above = old_bottom;
 | 
			
		||||
          top_window = old_bottom;
 | 
			
		||||
          paint_and_above(top_window);
 | 
			
		||||
          break;
 | 
			
		||||
        case WM_MOVE_LEFT:
 | 
			
		||||
          if (top_window) {
 | 
			
		||||
            top_window->xpos -= MOVE_BY;
 | 
			
		||||
| 
						 | 
				
			
			@ -488,3 +505,47 @@ void on_action(struct window_action packet) {
 | 
			
		|||
  if (top_window)
 | 
			
		||||
    send_action(top_window, packet);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void move_mouse_by(int16_t y, int16_t x) {
 | 
			
		||||
//logf(LOG_INFO, "old mouse coords: (%d, %d)", mouse_x, mouse_y);
 | 
			
		||||
  switch_to_kernel_cr3();
 | 
			
		||||
  blit(mouse_x, mouse_x + MOUSE_WIDTH  > VBE_MODE_INFO->width  ? VBE_MODE_INFO->width  : mouse_x + MOUSE_WIDTH,
 | 
			
		||||
       mouse_y, mouse_y + MOUSE_HEIGHT > VBE_MODE_INFO->height ? VBE_MODE_INFO->height : mouse_y + MOUSE_HEIGHT);
 | 
			
		||||
  mouse_y = (-y > mouse_y) ? 0 : (y + mouse_y + MOUSE_HEIGHT > VBE_MODE_INFO->height) ? VBE_MODE_INFO->height - MOUSE_HEIGHT : y + mouse_y;
 | 
			
		||||
  mouse_x = (-x > mouse_x) ? 0 : (x + mouse_x + MOUSE_WIDTH  > VBE_MODE_INFO->width)  ? VBE_MODE_INFO->width  - MOUSE_WIDTH  : x + mouse_x;
 | 
			
		||||
  blit_mouse();
 | 
			
		||||
  switch_to_task_cr3();
 | 
			
		||||
//logf(LOG_INFO, "new mouse coords: (%d, %d)", mouse_x, mouse_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void focus(struct window *w) {
 | 
			
		||||
  send_action(top_window, (struct window_action){.action_type = FOCUS_LEAVE});
 | 
			
		||||
 | 
			
		||||
  if (w->below)
 | 
			
		||||
    w->below->above = w->above;
 | 
			
		||||
  else
 | 
			
		||||
    bottom_window = w->above;
 | 
			
		||||
  w->above->below = w->below;
 | 
			
		||||
  w->above = 0;
 | 
			
		||||
  w->below = top_window;
 | 
			
		||||
  top_window->above = w;
 | 
			
		||||
  top_window = w;
 | 
			
		||||
 | 
			
		||||
  send_action(w, (struct window_action){.action_type = FOCUS_ENTER});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mouse_button(enum mouse_button which, bool up) {
 | 
			
		||||
  if (!top_window)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  struct window *const clicked_on = buffer[mouse_y * VBE_MODE_INFO->width + mouse_x].from_window;
 | 
			
		||||
  if (!clicked_on)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (clicked_on != top_window) {
 | 
			
		||||
    focus(clicked_on);
 | 
			
		||||
    paint_and_above(clicked_on);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  send_action(clicked_on, (struct window_action){.action_type = up ? MOUSE_UP : MOUSE_DOWN, .as_mouse = {.y = mouse_y - clicked_on->ypos, .x = mouse_x - clicked_on->xpos, .which = which}});
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -33,4 +33,7 @@ void delete_any_windows_from(struct task_state *tstate);
 | 
			
		|||
 | 
			
		||||
void show_shutdown();
 | 
			
		||||
 | 
			
		||||
void move_mouse_by(int16_t y, int16_t x);
 | 
			
		||||
void mouse_button(enum mouse_button which, bool up);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,10 +9,20 @@ struct window_action {
 | 
			
		|||
    KEY_DOWN,
 | 
			
		||||
    KEY_UP,
 | 
			
		||||
    FOCUS_ENTER,
 | 
			
		||||
    FOCUS_LEAVE
 | 
			
		||||
    FOCUS_LEAVE,
 | 
			
		||||
    MOUSE_DOWN,
 | 
			
		||||
    MOUSE_UP
 | 
			
		||||
  } action_type;
 | 
			
		||||
  union {
 | 
			
		||||
    struct key_packet as_key;
 | 
			
		||||
    struct {
 | 
			
		||||
      //0, 0 is upper-left-most pixel not counting border
 | 
			
		||||
      //packets are also sent for the border pixels,
 | 
			
		||||
      //  so this may be a negative value in those cases
 | 
			
		||||
      int16_t y;
 | 
			
		||||
      int16_t x;
 | 
			
		||||
      enum mouse_button {LEFT, RIGHT, MIDDLE} which;
 | 
			
		||||
    } as_mouse;
 | 
			
		||||
  };
 | 
			
		||||
} __attribute__ ((__packed__));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,8 +42,8 @@ struct format_spec {
 | 
			
		|||
    CHAR,
 | 
			
		||||
    STRING,
 | 
			
		||||
    UNSIGNED_DECIMAL,
 | 
			
		||||
    HEXADECIMAL
 | 
			
		||||
    //TODO: signed decimal
 | 
			
		||||
    HEXADECIMAL,
 | 
			
		||||
    SIGNED_DECIMAL
 | 
			
		||||
  } kind;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +73,9 @@ static const char *get_format(const char *from, struct format_spec *format_out)
 | 
			
		|||
  case 'x':
 | 
			
		||||
    format_out->kind = HEXADECIMAL;
 | 
			
		||||
    break;
 | 
			
		||||
  case 'd':
 | 
			
		||||
    format_out->kind = SIGNED_DECIMAL;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    format_out->kind = UNKNOWN;
 | 
			
		||||
    break;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +84,17 @@ static const char *get_format(const char *from, struct format_spec *format_out)
 | 
			
		|||
  return from + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//char debug[] = "-- format_v: fmt = \"   \"...";
 | 
			
		||||
static uint8_t get_digits(uint32_t k) {
 | 
			
		||||
  if (k >= 1000000000)
 | 
			
		||||
    return 10;
 | 
			
		||||
  uint8_t r = 1;
 | 
			
		||||
  uint32_t n = 10;
 | 
			
		||||
  while (k >= n) {
 | 
			
		||||
    ++r;
 | 
			
		||||
    n *= 10;
 | 
			
		||||
  }
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//allocates new memory
 | 
			
		||||
char *format_v(const char *fmt, va_list args) {
 | 
			
		||||
| 
						 | 
				
			
			@ -92,11 +105,6 @@ char *format_v(const char *fmt, va_list args) {
 | 
			
		|||
  buf_i = buf;
 | 
			
		||||
 | 
			
		||||
  while (*fmt) {
 | 
			
		||||
  //debug[20] = *fmt;
 | 
			
		||||
  //debug[21] = fmt[1];
 | 
			
		||||
  //debug[22] = fmt[2];
 | 
			
		||||
  //_system_log(debug);
 | 
			
		||||
 | 
			
		||||
    if (*fmt != '%') {
 | 
			
		||||
      ensure(1);
 | 
			
		||||
      *(buf_i++) = *(fmt++);
 | 
			
		||||
| 
						 | 
				
			
			@ -137,20 +145,24 @@ char *format_v(const char *fmt, va_list args) {
 | 
			
		|||
        continue;
 | 
			
		||||
 | 
			
		||||
        uint32_t k;
 | 
			
		||||
      case SIGNED_DECIMAL:
 | 
			
		||||
        k = va_arg(args, uint32_t);
 | 
			
		||||
        bool is_neg = k & 0x80000000;
 | 
			
		||||
        if (is_neg) {
 | 
			
		||||
          ensure(1);
 | 
			
		||||
          *(buf_i++) = '-';
 | 
			
		||||
          k = -k;
 | 
			
		||||
        }
 | 
			
		||||
        if (!form.len)
 | 
			
		||||
          form.len = get_digits(k);
 | 
			
		||||
        else if (is_neg)
 | 
			
		||||
          --form.len;
 | 
			
		||||
        goto print_dec;
 | 
			
		||||
      case UNSIGNED_DECIMAL:
 | 
			
		||||
        k = va_arg(args, uint32_t);
 | 
			
		||||
        if (!form.len) {
 | 
			
		||||
          if (k >= 1000000000)
 | 
			
		||||
            form.len = 10;
 | 
			
		||||
          else {
 | 
			
		||||
            uint32_t n = 10;
 | 
			
		||||
            ++form.len;
 | 
			
		||||
            while (k >= n) {
 | 
			
		||||
              ++form.len;
 | 
			
		||||
              n *= 10;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (!form.len)
 | 
			
		||||
          form.len = get_digits(k);
 | 
			
		||||
      print_dec:
 | 
			
		||||
        ensure(form.len);
 | 
			
		||||
        const uint32_t len_backup = form.len;
 | 
			
		||||
        while (form.len--) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										42
									
								
								src/user/mdemo/main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/user/mdemo/main.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
#include <pland/syscall.h>
 | 
			
		||||
#include <popups/info.h>
 | 
			
		||||
 | 
			
		||||
#define TEXT_COLOR ((_pixel_t){.r = 0x00, .g = 0x00, .b = 0x00})
 | 
			
		||||
#define BG_COLOR   ((_pixel_t){.r = 0xbf, .g = 0xbf, .b = 0xbf})
 | 
			
		||||
 | 
			
		||||
static const char *const mb_names[] = {
 | 
			
		||||
  "left", "right", "middle"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
  struct popup main_win;
 | 
			
		||||
  info_popup(&main_win, "Click me!", TEXT_COLOR, BG_COLOR);
 | 
			
		||||
 | 
			
		||||
  while (1) {
 | 
			
		||||
    struct window_action winact;
 | 
			
		||||
    _get_win_action(main_win.handle, &winact);
 | 
			
		||||
 | 
			
		||||
    switch (winact.action_type) {
 | 
			
		||||
      struct popup modal;
 | 
			
		||||
    case NOT_READY:
 | 
			
		||||
      _wait_for_action();
 | 
			
		||||
      _yield_task();
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    case KEY_DOWN:
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
    case MOUSE_DOWN:
 | 
			
		||||
      info_popupf(&modal,
 | 
			
		||||
        "Got %s click at (%d, %d)!",
 | 
			
		||||
        TEXT_COLOR, BG_COLOR,
 | 
			
		||||
        mb_names[winact.as_mouse.which],
 | 
			
		||||
        winact.as_mouse.x, winact.as_mouse.y);
 | 
			
		||||
      make_modal(&modal);
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in a new issue