| /**************************************************************************** |
| * apps/graphics/nuttx/pdcscrn.c |
| * |
| * Copyright (C) 2017 Gregory Nutt. All rights reserved. |
| * Author: Gregory Nutt <gnutt@nuttx.org> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * 3. Neither the name NuttX nor the names of its contributors may be |
| * used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/ioctl.h> |
| #include <sys/mman.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <string.h> |
| |
| #include <graphics/curses.h> |
| #include "pdcnuttx.h" |
| |
| /**************************************************************************** |
| * Public Data |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| #ifndef CONFIG_PDCURSES_MULTITHREAD |
| bool graphic_screen = false; |
| #endif |
| #endif |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: PDC_scr_free_term |
| * |
| * Description: |
| * Frees the memory for SP allocated by PDC_scr_open(). Called by |
| * delscreen(). |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| static void PDC_scr_free_term(FAR SCREEN *sp) |
| { |
| FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)sp; |
| FAR struct pdc_termstate_s *termstate = &termscreen->termstate; |
| |
| /* Deinitialize termcurses */ |
| |
| termcurses_deinitterm(termstate->tcurs); |
| |
| /* Free the memory */ |
| |
| free(termscreen); |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| PDC_ctx_free(); |
| #endif |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: PDC_scr_open_term |
| * |
| * Description: |
| * The platform-specific part of initscr(). It's actually called from |
| * Xinitscr(); the arguments, if present, correspond to those used with |
| * main(), and may be used to set the title of the terminal window, or for |
| * other, platform-specific purposes. This opens a terminal type screen |
| * backed by the NuttX termcurses interface.) PDC_scr_open() must allocate |
| * memory for SP, and must initialize acs_map[] (unless it's preset) and |
| * several members of SP, * including lines, cols, mouse_wait, orig_attr |
| * (and if orig_attr is true, orig_fore and orig_back), mono, _restore and |
| * _preserve. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| static int PDC_scr_open_term(int argc, char **argv) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| int ret; |
| int i; |
| struct winsize winsz; |
| FAR struct pdc_termscreen_s *termscreen; |
| FAR struct pdc_termstate_s *termstate; |
| FAR char *term_type; |
| |
| /* Determine the terminal type */ |
| |
| if (argc > 1) |
| { |
| term_type = argv[1]; |
| } |
| else |
| { |
| term_type = NULL; |
| } |
| |
| /* Allocate the SP */ |
| |
| termscreen = (FAR struct pdc_termscreen_s *) |
| zalloc(sizeof(struct pdc_termscreen_s)); |
| |
| if (termscreen == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to allocate SP\n")); |
| return ERR; |
| } |
| |
| termstate = &termscreen->termstate; |
| |
| /* Try to initialize termcurses on stdout */ |
| |
| ret = termcurses_initterm(term_type, 0, 1, &termstate->tcurs); |
| if (ret != OK) |
| { |
| PDC_LOG(("ERROR: Failed to initialize termcurses based SP\n")); |
| free(termscreen); |
| return ERR; |
| } |
| |
| /* Try to get the terminal size in rows / cols */ |
| |
| ret = termcurses_getwinsize(termstate->tcurs, &winsz); |
| if (ret != OK) |
| { |
| PDC_LOG(("ERROR: Terminal termcurses driver doesn't support size reporting\n")); |
| free(termscreen); |
| return ERR; |
| } |
| |
| graphic_screen = false; |
| SP = &termscreen->screen; |
| SP->lines = winsz.ws_row; |
| SP->cols = winsz.ws_col; |
| termscreen->termstate.out_fd = 1; |
| termscreen->termstate.in_fd = 0; |
| termscreen->termstate.fg_red = 0xFFFE; |
| termscreen->termstate.bg_red = 0xFFFE; |
| termstate = &termscreen->termstate; |
| |
| /* Setup initial RGB colors */ |
| |
| for (i = 0; i < 8; i++) |
| { |
| #ifdef PDCURSES_MONOCHROME |
| uint8_t greylevel; |
| |
| greylevel = (i & COLOR_RED) ? 0x40 : 0; |
| greylevel += (i & COLOR_GREEN) ? 0x40 : 0; |
| greylevel += (i & COLOR_BLUE) ? 0x40 : 0; |
| |
| termstate->greylevel[i] = greylevel; |
| termstate->greylevel[i+8] = greylevel | 0x3f; |
| #else |
| termstate->rgbcolor[i].red = (i & COLOR_RED) ? 0xc0 : 0; |
| termstate->rgbcolor[i].green = (i & COLOR_GREEN) ? 0xc0 : 0; |
| termstate->rgbcolor[i].blue = (i & COLOR_BLUE) ? 0xc0 : 0; |
| |
| termstate->rgbcolor[i + 8].red = (i & COLOR_RED) ? 0xff : 0x40; |
| termstate->rgbcolor[i + 8].green = (i & COLOR_GREEN) ? 0xff : 0x40; |
| termstate->rgbcolor[i + 8].blue = (i & COLOR_BLUE) ? 0xff : 0x40; |
| #endif |
| } |
| |
| COLORS = 16; |
| |
| #ifdef CONFIG_PDCURSES_HAVE_INPUT |
| ret = PDC_input_open(NULL); |
| if (ret != OK) |
| { |
| /* Free the memory ... can't open input */ |
| |
| PDC_ctx_free(); |
| free(termscreen); |
| } |
| #endif |
| |
| return ret; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| /**************************************************************************** |
| * Name: PDC_init_pair_term |
| * |
| * Description: |
| * The core of init_pair(). This does all the work of that function, except |
| * checking for values out of range. The values passed to this function |
| * should be returned by a call to PDC_pair_content() with the same pair |
| * number. PDC_transform_line() should use the specified colors when |
| * rendering a chtype with the given pair number. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| static void PDC_init_pair_term(FAR SCREEN *sp, short pair, short fg, short bg) |
| { |
| FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)sp; |
| |
| termscreen->termstate.colorpair[pair].fg = fg; |
| termscreen->termstate.colorpair[pair].bg = bg; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| /**************************************************************************** |
| * Name: PDC_init_color |
| * |
| * Description: |
| * The core of init_color(). This does all the work of that function, |
| * except checking for values out of range. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| int PDC_init_color_term(FAR SCREEN *sp, short color, short red, short green, |
| short blue) |
| { |
| FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)sp; |
| FAR struct pdc_termstate_s *termstate; |
| |
| DEBUGASSERT(termscreen != NULL); |
| termstate = &termscreen->termstate; |
| |
| #ifdef PDCURSES_MONOCHROME |
| greylevel = (DIVROUND(red * 255, 1000) + |
| DIVROUND(green * 255, 1000) + |
| DIVROUND(blue * 255, 1000)) / 3; |
| termstate->greylevel[color] = (uint8_t)greylevel; |
| #else |
| termstate->rgbcolor[color].red = DIVROUND(red * 255, 1000); |
| termstate->rgbcolor[color].green = DIVROUND(green * 255, 1000); |
| termstate->rgbcolor[color].blue = DIVROUND(blue * 255, 1000); |
| #endif |
| |
| return OK; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| /**************************************************************************** |
| * Name: PDC_color_content_term |
| * |
| * Description: |
| * The core of color_content(). This does all the work of that function, |
| * except checking for values out of range and null pointers. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| int PDC_color_content_term(FAR SCREEN *sp, short color, |
| FAR short *red, FAR short *green, FAR short *blue) |
| { |
| FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)sp; |
| FAR struct pdc_termstate_s *termstate; |
| |
| DEBUGASSERT(termscreen != NULL); |
| termstate = &termscreen->termstate; |
| |
| #ifdef PDCURSES_MONOCHROME |
| greylevel = DIVROUND(termstate->greylevel[color] * 1000, 255); |
| *red = greylevel; |
| *green = greylevel; |
| *blue = greylevel; |
| #else |
| *red = DIVROUND(termstate->rgbcolor[color].red * 1000, 255); |
| *green = DIVROUND(termstate->rgbcolor[color].green * 1000, 255); |
| *blue = DIVROUND(termstate->rgbcolor[color].blue * 1000, 255); |
| #endif |
| |
| return OK; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| /**************************************************************************** |
| * Name: PDC_pair_content_term |
| * |
| * Description: |
| * The core of pair_content(). This does all the work of that function, |
| * except checking for values out of range and null pointers. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| static int PDC_pair_content_term(FAR SCREEN *sp, short pair, short *fg, short *bg) |
| { |
| FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)sp; |
| |
| *fg = termscreen->termstate.colorpair[pair].fg; |
| *bg = termscreen->termstate.colorpair[pair].bg; |
| return OK; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: PDC_scr_close |
| * |
| * Description: |
| * The platform-specific part of endwin(). It may restore the image of the |
| * original screen saved by PDC_scr_open(), if the PDC_RESTORE_SCREEN |
| * environment variable is set; either way, if using an existing terminal, |
| * this function should restore it to the mode it had at startup, and move |
| * the cursor to the lower left corner. (The X11 port does nothing.) |
| * |
| ****************************************************************************/ |
| |
| void PDC_scr_close(void) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| PDC_LOG(("PDC_scr_close() - called\n")); |
| |
| /* Ensure cursor is visible */ |
| |
| curs_set(1); |
| attrset(COLOR_PAIR(0)); |
| |
| /* Delete the screen */ |
| |
| delscreen(SP); |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_scr_free |
| * |
| * Description: |
| * Frees the memory for SP allocated by PDC_scr_open(). Called by |
| * delscreen(). |
| * |
| ****************************************************************************/ |
| |
| void PDC_scr_free(void) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; |
| FAR struct pdc_fbstate_s *fbstate; |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| if (!graphic_screen) |
| { |
| PDC_scr_free_term(SP); |
| return; |
| } |
| |
| #endif |
| |
| DEBUGASSERT(fbscreen != NULL); |
| fbstate = &fbscreen->fbstate; |
| |
| close(fbstate->fbfd); |
| #ifdef CONFIG_PDCURSES_HAVE_INPUT |
| PDC_input_close(fbstate); |
| #endif |
| free(fbscreen); |
| SP = NULL; |
| |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| PDC_ctx_free(); |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_scr_open |
| * |
| * Description: |
| * The platform-specific part of initscr(). It's actually called from |
| * Xinitscr(); the arguments, if present, correspond to those used with |
| * main(), and may be used to set the title of the terminal window, or for |
| * other, platform-specific purposes. (The arguments are currently used |
| * only in X11.) PDC_scr_open() must allocate memory for SP, and must |
| * initialize acs_map[] (unless it's preset) and several members of SP, |
| * including lines, cols, mouse_wait, orig_attr (and if orig_attr is true, |
| * orig_fore and orig_back), mono, _restore and _preserve. (Although SP is |
| * used the same way in all ports, it's allocated here in order to allow |
| * the X11 port to map it to a block of shared memory.) If using an |
| * existing terminal, and the environment variable PDC_RESTORE_SCREEN is |
| * set, this function may also store the existing screen image for later |
| * restoration by PDC_scr_close(). |
| * |
| ****************************************************************************/ |
| |
| int PDC_scr_open(int argc, char **argv) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| FAR char *env_display; |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen; |
| FAR const struct nx_font_s *fontset; |
| FAR struct pdc_fbstate_s *fbstate; |
| struct fb_videoinfo_s vinfo; |
| struct fb_planeinfo_s pinfo; |
| int ret; |
| int i; |
| |
| PDC_LOG(("PDC_scr_open() - called\n")); |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| /* When termcurses is compiled in, we must allow opening terminal |
| * type screens also. Check if the DISPLAY environment variable is |
| * set to ":0" indicating we should open the graphic screen. |
| */ |
| |
| env_display = getenv("DISPLAY"); |
| if (!env_display || strcmp(env_display, ":0") != 0) |
| { |
| /* Perform terminal open operation */ |
| |
| return PDC_scr_open_term(argc, argv); |
| } |
| #endif |
| |
| /* Allocate the global instance of SP */ |
| |
| fbscreen = (FAR struct pdc_fbscreen_s *)zalloc(sizeof(struct pdc_fbscreen_s)); |
| if (fbscreen == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to allocate SP\n")); |
| return ERR; |
| } |
| |
| SP = &fbscreen->screen; |
| fbstate = &fbscreen->fbstate; |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| graphic_screen = true; |
| #endif |
| |
| /* Number of RGB colors/greyscale levels. This is the same as the |
| * dimension of rgbcolor[] or greylevel[]). |
| */ |
| |
| COLORS = 16; |
| |
| /* Setup initial RGB colors */ |
| |
| for (i = 0; i < 8; i++) |
| { |
| #ifdef PDCURSES_MONOCHROME |
| uint8_t greylevel; |
| |
| greylevel = (i & COLOR_RED) ? 0x40 : 0; |
| greylevel += (i & COLOR_GREEN) ? 0x40 : 0; |
| greylevel += (i & COLOR_BLUE) ? 0x40 : 0; |
| |
| fbstate->greylevel[i] = greylevel; |
| fbstate->greylevel[i+8] = greylevel | 0x3f; |
| #else |
| fbstate->rgbcolor[i].red = (i & COLOR_RED) ? 0xc0 : 0; |
| fbstate->rgbcolor[i].green = (i & COLOR_GREEN) ? 0xc0 : 0; |
| fbstate->rgbcolor[i].blue = (i & COLOR_BLUE) ? 0xc0 : 0; |
| |
| fbstate->rgbcolor[i + 8].red = (i & COLOR_RED) ? 0xff : 0x40; |
| fbstate->rgbcolor[i + 8].green = (i & COLOR_GREEN) ? 0xff : 0x40; |
| fbstate->rgbcolor[i + 8].blue = (i & COLOR_BLUE) ? 0xff : 0x40; |
| #endif |
| } |
| |
| /* Open the framebuffer driver */ |
| |
| fbstate->fbfd = open(CONFIG_PDCURSES_FBDEV, O_RDWR); |
| if (fbstate->fbfd < 0) |
| { |
| PDC_LOG(("ERROR: Failed to open %s: %d\n", |
| CONFIG_PDCURSES_FBDEV, errno)); |
| goto errout_with_sp; |
| } |
| |
| /* Get the characteristics of the framebuffer */ |
| |
| ret = ioctl(fbstate->fbfd, FBIOGET_VIDEOINFO, |
| (unsigned long)((uintptr_t)&vinfo)); |
| if (ret < 0) |
| { |
| PDC_LOG(("ERROR: ioctl(FBIOGET_VIDEOINFO) failed: %d\n", errno)); |
| goto errout_with_fbfd; |
| } |
| |
| PDC_LOG(("VideoInfo:\n")); |
| PDC_LOG((" fmt: %u\n", vinfo.fmt)); |
| PDC_LOG((" xres: %u\n", vinfo.xres)); |
| PDC_LOG((" yres: %u\n", vinfo.yres)); |
| PDC_LOG((" nplanes: %u\n", vinfo.nplanes)); |
| |
| fbstate->xres = vinfo.xres; /* Horizontal resolution in pixel columns */ |
| fbstate->yres = vinfo.yres; /* Vertical resolution in pixel rows */ |
| |
| /* Only one color format supported. */ |
| |
| if (vinfo.fmt != PDCURSES_COLORFMT) |
| { |
| PDC_LOG(("ERROR: color format=%u not supported\n", vinfo.fmt)); |
| goto errout_with_fbfd; |
| } |
| |
| #ifdef PDCURSES_MONOCHROME |
| /* Remember if we are using a monochrome framebuffer */ |
| |
| SP->mono = true; |
| #endif |
| |
| /* Get characteristics of the color plane */ |
| |
| ret = ioctl(fbstate->fbfd, FBIOGET_PLANEINFO, |
| (unsigned long)((uintptr_t)&pinfo)); |
| if (ret < 0) |
| { |
| PDC_LOG(("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", errno)); |
| goto errout_with_fbfd; |
| } |
| |
| PDC_LOG(("PlaneInfo (plane 0):\n")); |
| PDC_LOG((" fbmem: %p\n", pinfo.fbmem)); |
| PDC_LOG((" fblen: %lu\n", (unsigned long)pinfo.fblen)); |
| PDC_LOG((" stride: %u\n", pinfo.stride)); |
| PDC_LOG((" display: %u\n", pinfo.display)); |
| PDC_LOG((" bpp: %u\n", pinfo.bpp)); |
| |
| fbstate->stride = pinfo.stride; /* Length of a line in bytes */ |
| |
| /* Only one pixel depth is supported. */ |
| |
| if (pinfo.bpp != PDCURSES_BPP) |
| { |
| PDC_LOG(("ERROR: bpp=%u not supported\n", pinfo.bpp)); |
| goto errout_with_fbfd; |
| } |
| |
| /* mmap() the framebuffer. |
| * |
| * NOTE: In the FLAT build the frame buffer address returned by the |
| * FBIOGET_PLANEINFO IOCTL command will be the same as the framebuffer |
| * address. mmap(), however, is the preferred way to get the framebuffer |
| * address because in the KERNEL build, it will perform the necessary |
| * address mapping to make the memory accessible to the application. |
| */ |
| |
| fbstate->fbmem = mmap(NULL, pinfo.fblen, PROT_READ|PROT_WRITE, |
| MAP_SHARED|MAP_FILE, fbstate->fbfd, 0); |
| if (fbstate->fbmem == MAP_FAILED) |
| { |
| PDC_LOG(("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", errno)); |
| goto errout_with_fbfd; |
| } |
| |
| PDC_LOG(("Mapped FB: %p\n", fbstate->fbmem)); |
| |
| /* Get the handle for the selected font */ |
| |
| fbstate->hfont = nxf_getfonthandle(PDCURSES_FONTID); |
| if (fbstate->hfont == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to get font handle: %d\n", errno)); |
| goto errout_with_fbfd; |
| } |
| |
| #ifdef HAVE_BOLD_FONT |
| /* Get the handle for the matching bold font. It is assume that the |
| * geometry of the bold font is exactly the same as the geometry of |
| * the "normal" font. |
| */ |
| |
| fbstate->hbold = nxf_getfonthandle(PDCURSES_BOLD_FONTID); |
| if (fbstate->hbold == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to get font handle: %d\n", errno)); |
| goto errout_with_font; |
| } |
| #endif |
| |
| /* Get information about the fontset */ |
| |
| fontset = nxf_getfontset(fbstate->hfont); |
| if (fontset == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to get font handle: %d\n", errno)); |
| goto errout_with_boldfont; |
| } |
| |
| PDC_LOG(("Fontset (ID=%d):\n", PDCURSES_FONTID)); |
| PDC_LOG((" mxheight: %u\n", fontset->mxheight)); |
| PDC_LOG((" mxwidth: %u\n", fontset->mxwidth)); |
| PDC_LOG((" mxbits: %u\n", fontset->mxbits)); |
| PDC_LOG((" spwidth: %u\n", fontset->spwidth)); |
| |
| fbstate->fheight = fontset->mxheight; |
| fbstate->fwidth = fontset->mxwidth; |
| |
| #if PDCURSES_BPP < 8 |
| /* Allocate the font buffer for < 8-bit display */ |
| |
| fbstate->fstride = |
| (fbstate->fwidth + PDCURSES_PPB_MASK) >> PDCURSES_PPB_SHIFT; |
| fbstate->fbuffer = (FAR uint8_t *) |
| malloc(fbstate->fstride * fbstate->fheight); |
| |
| if (fbstate->fbuffer == NULL) |
| { |
| PDC_LOG(("ERROR: Failed to allocate fstride: %d\n", errno)); |
| goto errout_with_boldfont; |
| } |
| #endif |
| |
| /* Calculate the drawable region */ |
| |
| SP->lines = fbstate->yres / fbstate->fheight; |
| SP->cols = fbstate->xres / fbstate->fwidth; |
| |
| fbstate->hoffset = (fbstate->xres - fbstate->fwidth * SP->cols) / 2; |
| fbstate->voffset = (fbstate->yres - fbstate->fheight * SP->lines) / 2; |
| |
| /* Set the framebuffer to a known state */ |
| |
| PDC_clear_screen(fbstate); |
| |
| #ifdef CONFIG_PDCURSES_HAVE_INPUT |
| /* Open and configure any input devices */ |
| |
| ret = PDC_input_open(fbstate); |
| if (ret == ERR) |
| { |
| goto errout_with_fbuffer; |
| } |
| #endif |
| |
| return OK; |
| |
| #ifdef CONFIG_PDCURSES_HAVE_INPUT |
| errout_with_fbuffer: |
| #if PDCURSES_BPP < 8 |
| free(fbstate->fbuffer); |
| #endif |
| #endif |
| |
| errout_with_boldfont: |
| #ifdef HAVE_BOLD_FONT |
| errout_with_font: |
| #endif |
| |
| errout_with_fbfd: |
| close(fbstate->fbfd); |
| fbstate->fbfd = -1; |
| |
| errout_with_sp: |
| free(SP); |
| SP = NULL; |
| return ERR; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_resize_screen |
| * |
| * Description: |
| * This does the main work of resize_term(). It may respond to non-zero |
| * parameters, by setting the screen to the specified size; to zero |
| * parameters, by setting the screen to a size chosen by the user at |
| * runtime, in an unspecified way (e.g., by dragging the edges of the |
| * window); or both. It may also do nothing, if there's no appropriate |
| * action for the platform. |
| * |
| ****************************************************************************/ |
| |
| int PDC_resize_screen(int nlines, int ncols) |
| { |
| PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n", |
| nlines, ncols)); |
| |
| /* We cannot resize the hardware framebuffer */ |
| |
| return ERR; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_reset_prog_mode |
| * |
| * Description: |
| * The non-portable functionality of reset_prog_mode() is handled here -- |
| * whatever's not done in _restore_mode(). In current ports: In OS/2, this |
| * sets the keyboard to binary mode; in Win32, it enables or disables the |
| * mouse pointer to match the saved mode; in others it does nothing. |
| * |
| ****************************************************************************/ |
| |
| void PDC_reset_prog_mode(void) |
| { |
| PDC_LOG(("PDC_reset_prog_mode() - called.\n")); |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_reset_shell_mode |
| * |
| * Description: |
| * The same thing for reset_shell_mode() as PDC_reset_prog_mode(). In OS/2 |
| * and Win32, it restores the default console mode; in others it does |
| * nothing. |
| * |
| ****************************************************************************/ |
| |
| void PDC_reset_shell_mode(void) |
| { |
| PDC_LOG(("PDC_reset_shell_mode() - called.\n")); |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_restore_screen_mode |
| * |
| * Description: |
| * Called from _restore_mode() in pdc_kernel.c, this function does the |
| * actual mode changing, if applicable. Currently used only in DOS and |
| * OS/2. |
| * |
| ****************************************************************************/ |
| |
| void PDC_restore_screen_mode(int i) |
| { |
| PDC_LOG(("PDC_restore_screen_mode(). i=%d.\n", i)); |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_save_screen_mode |
| * |
| * Description: |
| * Called from _save_mode() in pdc_kernel.c, this function saves the actual |
| * screen mode, if applicable. Currently used only in DOS and OS/2. |
| * |
| ****************************************************************************/ |
| |
| void PDC_save_screen_mode(int i) |
| { |
| PDC_LOG(("PDC_save_screen_mode(). i=%d.\n", i)); |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_init_pair |
| * |
| * Description: |
| * The core of init_pair(). This does all the work of that function, except |
| * checking for values out of range. The values passed to this function |
| * should be returned by a call to PDC_pair_content() with the same pair |
| * number. PDC_transform_line() should use the specified colors when |
| * rendering a chtype with the given pair number. |
| * |
| ****************************************************************************/ |
| |
| void PDC_init_pair(short pair, short fg, short bg) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; |
| FAR struct pdc_fbstate_s *fbstate; |
| |
| PDC_LOG(("PDC_init_pair(). pair=%d, fg=%d, bg=%d\n", pair, fg, bg)); |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| if (!graphic_screen) |
| { |
| /* Process as terminal mode screen */ |
| |
| PDC_init_pair_term(SP, pair, fg, bg); |
| return; |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| DEBUGASSERT(fbscreen != NULL); |
| fbstate = &fbscreen->fbstate; |
| |
| fbstate->colorpair[pair].fg = fg; |
| fbstate->colorpair[pair].bg = bg; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_pair_content |
| * |
| * Description: |
| * The core of pair_content(). This does all the work of that function, |
| * except checking for values out of range and null pointers. |
| * |
| ****************************************************************************/ |
| |
| int PDC_pair_content(short pair, short *fg, short *bg) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; |
| FAR struct pdc_fbstate_s *fbstate; |
| |
| PDC_LOG(("PDC_pair_content(). pair=%d\n", pair)); |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| if (!graphic_screen) |
| { |
| /* Process as terminal mode screen */ |
| |
| return PDC_pair_content_term(SP, pair, fg, bg); |
| } |
| #endif /* CONFIG_SYSTEM_TERMCURSES */ |
| |
| DEBUGASSERT(fbscreen != NULL); |
| fbstate = &fbscreen->fbstate; |
| |
| *fg = fbstate->colorpair[pair].fg; |
| *bg = fbstate->colorpair[pair].bg; |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_can_change_color |
| * |
| * Description: |
| * Returns true if init_color() and color_content() give meaningful |
| * results, false otherwise. Called from can_change_color(). |
| * |
| ****************************************************************************/ |
| |
| bool PDC_can_change_color(void) |
| { |
| return true; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_color_content |
| * |
| * Description: |
| * The core of color_content(). This does all the work of that function, |
| * except checking for values out of range and null pointers. |
| * |
| ****************************************************************************/ |
| |
| int PDC_color_content(short color, short *red, short *green, short *blue) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; |
| FAR struct pdc_fbstate_s *fbstate; |
| #ifdef PDCURSES_MONOCHROME |
| short greylevel; |
| #endif |
| |
| PDC_LOG(("PDC_init_color(). color=%d\n", color)); |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| if (!graphic_screen) |
| { |
| /* Process as terminal mode screen */ |
| |
| return PDC_color_content_term(SP, color, red, green, blue); |
| } |
| #endif |
| |
| DEBUGASSERT(fbscreen != NULL); |
| fbstate = &fbscreen->fbstate; |
| |
| #ifdef PDCURSES_MONOCHROME |
| greylevel = DIVROUND(fbstate->greylevel[color] * 1000, 255); |
| *red = greylevel; |
| *green = greylevel; |
| *blue = greylevel; |
| #else |
| *red = DIVROUND(fbstate->rgbcolor[color].red * 1000, 255); |
| *green = DIVROUND(fbstate->rgbcolor[color].green * 1000, 255); |
| *blue = DIVROUND(fbstate->rgbcolor[color].blue * 1000, 255); |
| #endif |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: PDC_init_color |
| * |
| * Description: |
| * The core of init_color(). This does all the work of that function, |
| * except checking for values out of range. |
| * |
| ****************************************************************************/ |
| |
| int PDC_init_color(short color, short red, short green, short blue) |
| { |
| #ifdef CONFIG_PDCURSES_MULTITHREAD |
| FAR struct pdc_context_s *ctx = PDC_ctx(); |
| #endif |
| FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; |
| FAR struct pdc_fbstate_s *fbstate; |
| #ifdef PDCURSES_MONOCHROME |
| uint16_t greylevel; |
| #endif |
| |
| PDC_LOG(("PDC_init_color(). color=%d, red=%d, green=%d, blue=%d\n", |
| color, red, green, blue)); |
| |
| #ifdef CONFIG_SYSTEM_TERMCURSES |
| if (!graphic_screen) |
| { |
| /* Process as terminal mode screen */ |
| |
| return PDC_init_color_term(SP, color, red, green, blue); |
| } |
| #endif |
| |
| DEBUGASSERT(fbscreen != NULL); |
| fbstate = &fbscreen->fbstate; |
| |
| #ifdef PDCURSES_MONOCHROME |
| greylevel = (DIVROUND(red * 255, 1000) + |
| DIVROUND(green * 255, 1000) + |
| DIVROUND(blue * 255, 1000)) / 3; |
| fbstate->greylevel[color] = (uint8_t)greylevel; |
| #else |
| fbstate->rgbcolor[color].red = DIVROUND(red * 255, 1000); |
| fbstate->rgbcolor[color].green = DIVROUND(green * 255, 1000); |
| fbstate->rgbcolor[color].blue = DIVROUND(blue * 255, 1000); |
| #endif |
| |
| return OK; |
| } |