Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libraries/console][servers/console] Support double-buffering of console output #158

Merged
merged 1 commit into from
Jul 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libraries/console/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ OBJECTS = %w[

OUTPUT = 'libconsole.a'.freeze

ENV['EXTRA_CFLAGS'] = '-Wno-error=unused-parameter'

load '../libraries.rake'
105 changes: 103 additions & 2 deletions libraries/console/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdarg.h>
#include <console/console.h>
#include <ipc/ipc.h>
#include <memory/memory.h>
#include <string/string.h>

#define CONSOLE_MAILBOX_SIZE 32768
Expand All @@ -19,6 +20,8 @@ return_type console_init(console_structure_type *console_structure, tag_type *ta
unsigned int services = 10;
message_parameter_type message_parameter;

memory_set_uint8_t((uint8_t *) console_structure, 0, sizeof(console_structure_type));

console_structure->initialised = FALSE;

if (ipc_service_resolve("console", mailbox_id, &services, 5, tag) != IPC_RETURN_SUCCESS)
Expand Down Expand Up @@ -66,6 +69,33 @@ return_type console_open(console_structure_type *console_structure,

system_call_mailbox_send(console_structure->ipc_structure.output_mailbox_id, &message_parameter);

if (console_attribute.enable_buffer)
{
if (console_attribute.mode_type == VIDEO_MODE_TYPE_TEXT)
{
memory_allocate((void **) &console_structure->buffer,
console_attribute.width *
console_attribute.height *
sizeof(console_character_type));

// Ensure the newly allocated buffer is cleared. Note: we clear with zeroes instead 0f
// 0x0700 here (as is done on regular consoles by the console server), to deliberately
// avoid showing the cursor. Double-buffered applications are unlikely to want to
// display a text cursor anyway.
memory_set_uint16_t((uint16_t *) console_structure->buffer, 0,
console_attribute.width * console_attribute.height);
}
else
{
// Double-buffering is currently only supported for text-mode consoles.
return CONSOLE_RETURN_INVALID_ARGUMENT;
}
}

console_structure->opened = TRUE;
console_structure->width = console_attribute.width;
console_structure->height = console_attribute.height;

return CONSOLE_RETURN_SUCCESS;
}

Expand Down Expand Up @@ -200,7 +230,6 @@ return_type console_print(console_structure_type *console_structure, const char
return CONSOLE_RETURN_SUCCESS;
}

// Prints the given data to the console, a la printf and friends.
return_type console_print_formatted(console_structure_type *console_structure, const char *format_string, ...)
{
va_list arguments;
Expand All @@ -227,7 +256,6 @@ return_type console_clear(console_structure_type *console_structure)
return console_print(console_structure, "\e[2J\e[1;1H");
}

// Move the cursor. Zero indexed!!!
return_type console_cursor_move(console_structure_type *console_structure, unsigned int x, unsigned int y)
{
// FIXME: Should store the size of the console somewhere.
Expand Down Expand Up @@ -305,3 +333,76 @@ return_type console_event_wait(console_structure_type *console_structure, void *

return CONSOLE_RETURN_SUCCESS;
}

return_type console_buffer_print(console_structure_type *console_structure,
int x, int y, uint8_t attribute,
const char *string)
{
unsigned int position = (y * console_structure->width) + x;
unsigned int max_position = console_structure->width * console_structure->height;

for (unsigned int i = 0; i < string_length(string); i++)
{
if (position + i > max_position)
{
// We are past the end of the buffer. Abort and return an error to the caller.
return CONSOLE_RETURN_INVALID_ARGUMENT;
}

console_structure->buffer[position + i].character = string[i];
console_structure->buffer[position + i].attribute = attribute;
}

return CONSOLE_RETURN_SUCCESS;
}

return_type console_buffer_print_formatted(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *format_string, ...)
{
va_list arguments;

// FIXME: Don't have a hardwired buffer like this!
char output[1024];

if (format_string == NULL)
{
output[0] = '\0';

return CONSOLE_RETURN_INVALID_ARGUMENT;
}

va_start(arguments, format_string);
string_print_va(output, format_string, arguments);
va_end(arguments);

return console_buffer_print(console_structure, x, y, attribute, output);
}

return_type console_flip(console_structure_type *console_structure)
{
message_parameter_type message_parameter;

if (!console_structure->initialised)
{
return CONSOLE_RETURN_SERVICE_UNAVAILABLE;
}

if (console_structure->width <= 0 ||
console_structure->height <= 0)
{
return CONSOLE_RETURN_INVALID_ARGUMENT;
}

message_parameter.protocol = IPC_PROTOCOL_CONSOLE;
message_parameter.length = console_structure->width *
console_structure->height *
sizeof(console_character_type);
message_parameter.message_class = IPC_CONSOLE_OUTPUT_ALL;
message_parameter.data = (void *) console_structure->buffer;
message_parameter.block = TRUE;

system_call_mailbox_send(console_structure->ipc_structure.output_mailbox_id, &message_parameter);

return CONSOLE_RETURN_SUCCESS;
}
39 changes: 38 additions & 1 deletion libraries/console/defines.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Abstract: Defines used by the console library.
// Author: Per Lundberg <[email protected]>
//
// © Copyright 1999-2000, 2013 chaos development.
// © Copyright 1999 chaos development

#pragma once

// Welcome, to the Real World. In this, we use EGA colors in the year of 2KAD...
// FIXME: I wonder what this is, really. These are _neither_ EGA nor
// ANSI colours in reality. They resemble ANSI more than EGA but not
// 100%...
enum
{
CONSOLE_COLOUR_BLACK,
Expand All @@ -18,6 +21,40 @@ enum
CONSOLE_COLOUR_GRAY,
};

// These colours are used when working with buffered console output.
// Note that their numeral values are different to the ones above;
// this is used so that buffers can copied to EGA-compatible text
// mode hardware without conversion.
enum
{
CONSOLE_BUFFER_COLOUR_BLACK, // 0
CONSOLE_BUFFER_COLOUR_BLUE,
CONSOLE_BUFFER_COLOUR_GREEN,
CONSOLE_BUFFER_COLOUR_CYAN,
CONSOLE_BUFFER_COLOUR_RED,
CONSOLE_BUFFER_COLOUR_MAGENTA,
CONSOLE_BUFFER_COLOUR_BROWN,
CONSOLE_BUFFER_COLOUR_LIGHT_GRAY,

CONSOLE_BUFFER_COLOUR_DARK_GRAY, // 8
CONSOLE_BUFFER_COLOUR_BRIGHT_BLUE,
CONSOLE_BUFFER_COLOUR_BRIGHT_GREEN,
CONSOLE_BUFFER_COLOUR_BRIGHT_CYAN,
CONSOLE_BUFFER_COLOUR_BRIGHT_RED,
CONSOLE_BUFFER_COLOUR_BRIGHT_MAGENTA,
CONSOLE_BUFFER_COLOUR_BRIGHT_YELLOW,
CONSOLE_BUFFER_COLOUR_BRIGHT_WHITE,

CONSOLE_BUFFER_BG_COLOUR_BLACK, // 0x10
CONSOLE_BUFFER_BG_COLOUR_BLUE,
CONSOLE_BUFFER_BG_COLOUR_GREEN,
CONSOLE_BUFFER_BG_COLOUR_CYAN,
CONSOLE_BUFFER_BG_COLOUR_RED,
CONSOLE_BUFFER_BG_COLOUR_MAGENTA,
CONSOLE_BUFFER_BG_COLOUR_BROWN,
CONSOLE_BUFFER_BG_COLOUR_LIGHT_GRAY
};

enum
{
CONSOLE_ATTRIBUTE_RESET = 0,
Expand Down
23 changes: 23 additions & 0 deletions libraries/console/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ extern return_type console_mode_set(console_structure_type *console_structure, u
extern return_type console_resize(console_structure_type *console_structure, unsigned int width,
unsigned int height);
extern return_type console_print(console_structure_type *console_structure, const char *string);

// Prints the given data to the console, similar to printf.
extern return_type console_print_formatted(console_structure_type *console_structure,
const char *string, ...) __attribute__ ((format (printf, 2, 3)));
extern return_type console_clear(console_structure_type *console_structure);

// Moves the cursor. Note that the position is zero-indexed; the top-left coordinate is 0,0.
extern return_type console_cursor_move(console_structure_type *console_structure, unsigned int x,
unsigned int y);
extern return_type console_attribute_set(console_structure_type *console_structure, int foreground,
Expand All @@ -34,4 +38,23 @@ extern return_type console_use_mouse(console_structure_type *console_structure,
extern return_type console_event_wait(console_structure_type *console_structure, void *event_data,
int *type, bool block);

// Prints output to a console using double-buffering, at the given
// cursor position.
extern return_type console_buffer_print(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *string
);

// Prints printf-formatted output to a console using double-buffering, at
// the given cursor position.
extern return_type console_buffer_print_formatted(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *string, ...
) __attribute__ ((format (printf, 5, 6)));

// Flips double-buffered content to the "real" console. If this console
// uses double-buffering, this function must be called whenever a
// "frame" is ready to be displayed.
extern return_type console_flip(console_structure_type *console_structure);

C_EXTERN_END
13 changes: 12 additions & 1 deletion libraries/console/types.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// Abstract: Console library types.
// Author: Per Lundberg <[email protected]>
//
// © Copyright 2000 chaos development.
// © Copyright 1999 chaos development.

#pragma once

#include <ipc/ipc.h>

typedef struct
{
uint8_t character;
uint8_t attribute;
} PACKED console_character_type;

typedef struct
{
ipc_structure_type ipc_structure;
Expand All @@ -16,4 +22,9 @@ typedef struct
unsigned int type;
bool initialised;
bool opened;

// If ipc_console_attribute_type.enable_buffer was set when
// console_open was called, this will be a non-NULL pointer that
// will be used to double-buffer content.
console_character_type *buffer;
} console_structure_type;
24 changes: 16 additions & 8 deletions libraries/ipc/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum
IPC_CONSOLE_MODE_SET,
IPC_CONSOLE_CLOSE,
IPC_CONSOLE_OUTPUT,
IPC_CONSOLE_OUTPUT_ALL,
IPC_CONSOLE_RESIZE,
IPC_CONSOLE_ENABLE_KEYBOARD,
IPC_CONSOLE_DISABLE_KEYBOARD,
Expand Down Expand Up @@ -50,22 +51,29 @@ typedef struct
// Physical console attribute type.
typedef struct
{
// The width in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or characters (for VIDEO_MODE_TYPE_TEXT)
// of the console being opened.
// The width in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or characters
// (for VIDEO_MODE_TYPE_TEXT) of the console being opened.
unsigned int width;

// The height in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or lines (for VIDEO_MODE_TYPE_TEXT)
// of the console being opened.
// The height in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or lines (for
// VIDEO_MODE_TYPE_TEXT) of the console being opened.
unsigned int height;

// For VIDEO_MODE_TYPE_GRAPHIC, indicates the depth in bits (15, 16, 24 etc) of the mode being
// requested.
// For VIDEO_MODE_TYPE_GRAPHIC, indicates the depth in bits (15, 16,
// 24 etc) of the mode being requested.
unsigned int depth;

// Set to either VIDEO_MODE_TYPE_TEXT or VIDEO_MODE_TYPE_GRAPHIC.
unsigned int mode_type;

// Indicates that the console should be activated upon creation. Can only be done once; if
// a console is already active, this flag will be ignored by the console server.
// Indicates that the console should be activated upon creation. Can
// only be done once; if a console is already active, this flag will
// be ignored by the console server.
bool activate;

// Set to TRUE if the client desires a local buffer for
// double-buffering console output. This is useful in applications
// with a lot of console outputs and/or real-time visualization
// requirements.
bool enable_buffer;
} ipc_console_attribute_type;
8 changes: 4 additions & 4 deletions libraries/ipc/keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ enum
IPC_KEYBOARD_SPECIAL_KEY_NUM_LOCK,
IPC_KEYBOARD_SPECIAL_KEY_SCROLL_LOCK,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_7,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_8,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_8, // Up arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_9,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_MINUS,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_4,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_4, // Left arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_5,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_6,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_6, // Right arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_PLUS,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_1,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_2,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_2, // Down arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_3,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_0,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_DELETE,
Expand Down
4 changes: 1 addition & 3 deletions libraries/string/inlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

// I think much of this is ripped from "somewhere" though... so this is probably more GPL than BSD.

// © Copyright 2000 chaos development
// © Copyright 2007 chaos development
// © Copyright 2017 chaos development
// © Copyright 1999 chaos development

#pragma once

Expand Down
1 change: 1 addition & 0 deletions servers/system/console/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ OBJECTS = %w[
connection.o
console.o
console_output.o
console_output_all.o
].freeze

LIBRARIES = %w[
Expand Down
Loading