aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/multiple/Win32/gdisp_lld_Win32.c
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2013-10-28 11:03:39 +1000
committerinmarket <andrewh@inmarket.com.au>2013-10-28 11:03:39 +1000
commitb05a29f830008ab0e9a36d8384ed7cf4ea3fb18b (patch)
tree193e79f1d53638dad20ac86c1c2e18492311f6b6 /drivers/multiple/Win32/gdisp_lld_Win32.c
parent9e5ed28f98e7b0b3dbd46df7a62568dbaffab92a (diff)
downloaduGFX-b05a29f830008ab0e9a36d8384ed7cf4ea3fb18b.tar.gz
uGFX-b05a29f830008ab0e9a36d8384ed7cf4ea3fb18b.tar.bz2
uGFX-b05a29f830008ab0e9a36d8384ed7cf4ea3fb18b.zip
Rename GDISP driver files to prevent problems when compiling for multiple controllers on platforms that put all generated object files into a single directory.
Diffstat (limited to 'drivers/multiple/Win32/gdisp_lld_Win32.c')
-rw-r--r--drivers/multiple/Win32/gdisp_lld_Win32.c1163
1 files changed, 1163 insertions, 0 deletions
diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c
new file mode 100644
index 00000000..7d7abb06
--- /dev/null
+++ b/drivers/multiple/Win32/gdisp_lld_Win32.c
@@ -0,0 +1,1163 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file drivers/multiple/Win32/gdisp_lld.c
+ * @brief GDISP Graphics Driver subsystem low level driver source for Win32.
+ */
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#define GDISP_DRIVER_VMT GDISPVMT_Win32
+#include "../drivers/multiple/Win32/gdisp_lld_config.h"
+#include "gdisp/lld/gdisp_lld.h"
+
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 640
+#endif
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 480
+#endif
+#if GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888
+ #error "GDISP Win32: This driver currently only supports the RGB888 pixel format."
+#endif
+// Setting this to TRUE delays updating the screen
+// to the windows paint routine. Due to the
+// drawing lock this does not add as much speed
+// as might be expected but it is still faster in
+// all tested circumstances and for all operations
+// even draw_pixel().
+// This is probably due to drawing operations being
+// combined as the update regions are merged.
+// The only time you might want to turn this off is
+// if you are debugging drawing and want to see each
+// pixel as it is set.
+#define GDISP_WIN32_USE_INDIRECT_UPDATE TRUE
+//#define GDISP_WIN32_USE_INDIRECT_UPDATE FALSE
+
+// How far extra windows (multiple displays) should be offset from the first.
+#define DISPLAY_X_OFFSET 50
+#define DISPLAY_Y_OFFSET 50
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <wingdi.h>
+#include <assert.h>
+
+#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0)
+#define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1)
+#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2)
+#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
+ #define GDISP_FLG_WSTREAM (GDISP_FLG_DRIVER<<3)
+ #define GDISP_FLG_WRAPPED (GDISP_FLG_DRIVER<<4)
+#endif
+
+#if GINPUT_NEED_TOGGLE
+ /* Include toggle support code */
+ #include "ginput/lld/toggle.h"
+#endif
+
+#if GINPUT_NEED_MOUSE
+ /* Include mouse support code */
+ #include "ginput/lld/mouse.h"
+#endif
+
+static DWORD winThreadId;
+static ATOM winClass;
+static volatile bool_t QReady;
+static HANDLE drawMutex;
+#if GINPUT_NEED_MOUSE
+ static GDisplay * mouseDisplay;
+#endif
+
+/*===========================================================================*/
+/* Driver local routines . */
+/*===========================================================================*/
+
+#if GINPUT_NEED_TOGGLE
+ #define WIN32_BUTTON_AREA 16
+#else
+ #define WIN32_BUTTON_AREA 0
+#endif
+
+#define APP_NAME "uGFX"
+
+#define COLOR2BGR(c) ((((c) & 0xFF)<<16)|((c) & 0xFF00)|(((c)>>16) & 0xFF))
+#define BGR2COLOR(c) COLOR2BGR(c)
+
+typedef struct winPriv {
+ HWND hwnd;
+ HDC dcBuffer;
+ HBITMAP dcBitmap;
+ HBITMAP dcOldBitmap;
+ #if GINPUT_NEED_MOUSE
+ coord_t mousex, mousey;
+ uint16_t mousebuttons;
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ uint8_t toggles;
+ #endif
+ #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
+ coord_t x0, y0, x1, y1;
+ coord_t x, y;
+ #endif
+} winPriv;
+
+
+static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ HDC dc;
+ PAINTSTRUCT ps;
+ GDisplay * g;
+ winPriv * priv;
+ #if GINPUT_NEED_TOGGLE
+ HBRUSH hbrOn, hbrOff;
+ HPEN pen;
+ RECT rect;
+ HGDIOBJ old;
+ POINT p;
+ coord_t pos;
+ uint8_t bit;
+ #endif
+
+ switch (Msg) {
+ case WM_CREATE:
+ // Get our GDisplay structure and attach it to the window
+ g = (GDisplay *)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ priv = (winPriv *)g->priv;
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)g);
+
+ // Fill in the private area
+ priv->hwnd = hWnd;
+ dc = GetDC(hWnd);
+ priv->dcBitmap = CreateCompatibleBitmap(dc, g->g.Width, g->g.Height);
+ priv->dcBuffer = CreateCompatibleDC(dc);
+ ReleaseDC(hWnd, dc);
+ priv->dcOldBitmap = SelectObject(priv->dcBuffer, priv->dcBitmap);
+
+ // Mark the window as ready to go
+ g->flags |= GDISP_FLG_READY;
+ break;
+
+ #if GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE
+ case WM_LBUTTONDOWN:
+ // Get our GDisplay structure
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+
+ // Handle mouse down on the window
+ #if GINPUT_NEED_MOUSE
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons |= GINPUT_MOUSE_BTN_LEFT;
+ goto mousemove;
+ }
+ #endif
+
+ // Handle mouse down on the toggle area
+ #if GINPUT_NEED_TOGGLE
+ if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) {
+ bit = 1 << ((coord_t)LOWORD(lParam)*8/g->g.Width);
+ priv->toggles ^= bit;
+ rect.left = 0;
+ rect.right = GDISP_SCREEN_WIDTH;
+ rect.top = GDISP_SCREEN_HEIGHT;
+ rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
+ InvalidateRect(hWnd, &rect, FALSE);
+ UpdateWindow(hWnd);
+ #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE
+ ginputToggleWakeup();
+ #endif
+ }
+ #endif
+ break;
+
+ case WM_LBUTTONUP:
+ // Get our GDisplay structure
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+
+ // Handle mouse up on the toggle area
+ #if GINPUT_NEED_TOGGLE
+ if ((g->flags & GDISP_FLG_HASTOGGLE)) {
+ if ((priv->toggles & 0x0F)) {
+ priv->toggles &= ~0x0F;
+ rect.left = 0;
+ rect.right = GDISP_SCREEN_WIDTH;
+ rect.top = GDISP_SCREEN_HEIGHT;
+ rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
+ InvalidateRect(hWnd, &rect, FALSE);
+ UpdateWindow(hWnd);
+ #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE
+ ginputToggleWakeup();
+ #endif
+ }
+ }
+ #endif
+
+ // Handle mouse up on the window
+ #if GINPUT_NEED_MOUSE
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT;
+ goto mousemove;
+ }
+ #endif
+ break;
+ #endif
+
+ #if GINPUT_NEED_MOUSE
+ case WM_MBUTTONDOWN:
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE;
+ goto mousemove;
+ }
+ break;
+ case WM_MBUTTONUP:
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE;
+ goto mousemove;
+ }
+ break;
+ case WM_RBUTTONDOWN:
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons |= GINPUT_MOUSE_BTN_RIGHT;
+ goto mousemove;
+ }
+ break;
+ case WM_RBUTTONUP:
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+ if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) {
+ priv->mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT;
+ goto mousemove;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+ if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT || !(g->flags & GDISP_FLG_HASMOUSE))
+ break;
+ mousemove:
+ priv->mousex = (coord_t)LOWORD(lParam);
+ priv->mousey = (coord_t)HIWORD(lParam);
+ #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE
+ ginputMouseWakeup();
+ #endif
+ break;
+ #endif
+
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ break;
+ case WM_CHAR:
+ case WM_DEADCHAR:
+ case WM_SYSCHAR:
+ case WM_SYSDEADCHAR:
+ break;
+
+ case WM_ERASEBKGND:
+ // Pretend we have erased the background.
+ // We know we don't really need to do this as we
+ // redraw the entire surface in the WM_PAINT handler.
+ return TRUE;
+
+ case WM_PAINT:
+ // Get our GDisplay structure
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+
+ // Paint the main window area
+ WaitForSingleObject(drawMutex, INFINITE);
+ dc = BeginPaint(hWnd, &ps);
+ BitBlt(dc, ps.rcPaint.left, ps.rcPaint.top,
+ ps.rcPaint.right - ps.rcPaint.left,
+ (ps.rcPaint.bottom > GDISP_SCREEN_HEIGHT ? GDISP_SCREEN_HEIGHT : ps.rcPaint.bottom) - ps.rcPaint.top,
+ priv->dcBuffer, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
+
+ // Paint the toggle area
+ #if GINPUT_NEED_TOGGLE
+ if (ps.rcPaint.bottom >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) {
+ pen = CreatePen(PS_SOLID, 1, COLOR2BGR(Black));
+ hbrOn = CreateSolidBrush(COLOR2BGR(Blue));
+ hbrOff = CreateSolidBrush(COLOR2BGR(Gray));
+ old = SelectObject(dc, pen);
+ MoveToEx(dc, 0, GDISP_SCREEN_HEIGHT, &p);
+ LineTo(dc, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT);
+ for(pos = 0, bit=1; pos < wWidth; pos=rect.right, bit <<= 1) {
+ rect.left = pos;
+ rect.right = pos + GDISP_SCREEN_WIDTH/8;
+ rect.top = GDISP_SCREEN_HEIGHT;
+ rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
+ FillRect(dc, &rect, (priv->toggles & bit) ? hbrOn : hbrOff);
+ if (pos > 0) {
+ MoveToEx(dc, rect.left, rect.top, &p);
+ LineTo(dc, rect.left, rect.bottom);
+ }
+ }
+ DeleteObject(hbrOn);
+ DeleteObject(hbrOff);
+ SelectObject(dc, old);
+ }
+ #endif
+ EndPaint(hWnd, &ps);
+ ReleaseMutex(drawMutex);
+ break;
+
+ case WM_DESTROY:
+ // Get our GDisplay structure
+ g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ priv = (winPriv *)g->priv;
+
+ // Restore the window and free our bitmaps
+ SelectObject(priv->dcBuffer, priv->dcOldBitmap);
+ DeleteDC(priv->dcBuffer);
+ DeleteObject(priv->dcBitmap);
+
+ // Cleanup the private area
+ gfxFree(priv);
+
+ // Quit the application
+ PostQuitMessage(0);
+
+ // Actually the above doesn't work (who knows why)
+ ExitProcess(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
+ return 0;
+}
+
+static DECLARE_THREAD_STACK(waWindowThread, 1024);
+static DECLARE_THREAD_FUNCTION(WindowThread, param) {
+ (void)param;
+ MSG msg;
+
+ // Establish this thread as a message queue thread
+ winThreadId = GetCurrentThreadId();
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+ QReady = TRUE;
+
+ do {
+ gfxSleepMilliseconds(1);
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ // Is this our special thread message to create a new window?
+ if (!msg.hwnd && msg.message == WM_USER) {
+ RECT rect;
+ GDisplay *g;
+
+ g = (GDisplay *)msg.lParam;
+
+ // Set the window rectangle
+ rect.top = 0; rect.bottom = g->g.Height;
+ rect.left = 0; rect.right = g->g.Width;
+ #if GINPUT_NEED_TOGGLE
+ if ((g->flags & GDISP_FLG_HASTOGGLE))
+ rect.bottom += WIN32_BUTTON_AREA;
+ #endif
+ AdjustWindowRect(&rect, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0);
+
+ // Create the window
+ msg.hwnd = CreateWindow(APP_NAME, "", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_BORDER, msg.wParam*DISPLAY_X_OFFSET, msg.wParam*DISPLAY_Y_OFFSET,
+ rect.right-rect.left, rect.bottom-rect.top, 0, 0,
+ GetModuleHandle(NULL), g);
+ assert(msg.hwnd != NULL);
+
+ // Or just a normal window message
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ } while (msg.message != WM_QUIT);
+ ExitProcess(0);
+ return msg.wParam;
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
+ winPriv * priv;
+ char buf[132];
+
+ // Initialise the window thread and the window class (if it hasn't been done already)
+ if (!QReady) {
+ gfxThreadHandle hth;
+ WNDCLASS wc;
+
+ // Create the draw mutex
+ drawMutex = CreateMutex(NULL, FALSE, NULL);
+
+ // Create the thread
+ hth = gfxThreadCreate(waWindowThread, sizeof(waWindowThread), HIGH_PRIORITY, WindowThread, 0);
+ assert(hth != NULL);
+ gfxThreadClose(hth);
+
+ wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC;
+ wc.lpfnWndProc = (WNDPROC)myWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = APP_NAME;
+ winClass = RegisterClass(&wc);
+ assert(winClass != 0);
+
+ // Wait for our thread to be ready
+ while (!QReady)
+ Sleep(1);
+ }
+
+ // Initialise the GDISP structure
+ g->g.Orientation = GDISP_ROTATE_0;
+ g->g.Powermode = powerOn;
+ g->g.Backlight = 100;
+ g->g.Contrast = 50;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+
+ // Turn on toggles for the first GINPUT_TOGGLE_CONFIG_ENTRIES windows
+ #if GINPUT_NEED_TOGGLE
+ if (g->controllerdisplay < GINPUT_TOGGLE_CONFIG_ENTRIES)
+ g->flags |= GDISP_FLG_HASTOGGLE;
+ #endif
+
+ // Only turn on mouse on the first window for now
+ #if GINPUT_NEED_MOUSE
+ if (!g->controllerdisplay) {
+ mouseDisplay = g;
+ g->flags |= GDISP_FLG_HASMOUSE;
+ }
+ #endif
+
+ // Create a private area for this window
+ priv = (winPriv *)gfxAlloc(sizeof(winPriv));
+ assert(priv != NULL);
+ memset(priv, 0, sizeof(winPriv));
+ g->priv = priv;
+ #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
+ // Initialise with an invalid window
+ g->flags &= ~GDISP_FLG_WSTREAM;
+ #endif
+ g->board = 0; // no board interface for this controller
+
+ // Create the window in the message thread
+ PostThreadMessage(winThreadId, WM_USER, (WPARAM)g->controllerdisplay, (LPARAM)g);
+
+ // Wait for the window creation to complete (for safety)
+ while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY))
+ Sleep(1);
+
+ sprintf(buf, APP_NAME " - %u", g->systemdisplay+1);
+ SetWindowText(priv->hwnd, buf);
+ ShowWindow(priv->hwnd, SW_SHOW);
+ UpdateWindow(priv->hwnd);
+
+ return TRUE;
+}
+
+#if GDISP_HARDWARE_FLUSH
+ LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+ winPriv * priv;
+
+ priv = g->priv;
+ UpdateWindow(priv->hwnd);
+ }
+#endif
+
+#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
+ void BAD_PARAMETER(const char *msg) {
+ volatile int a;
+ // This is really just a point for us to set the debugger
+ a = 0;
+ }
+#endif
+
+#if GDISP_HARDWARE_STREAM_WRITE
+ LLDSPEC void gdisp_lld_write_start(GDisplay *g) {
+ winPriv * priv;
+
+ if (g->flags & GDISP_FLG_WSTREAM)
+ BAD_PARAMETER("write_start: already in streaming mode");
+ if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height)
+ BAD_PARAMETER("write_start: bad window parameter");
+
+ priv = g->priv;
+ priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1;
+ priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1;
+ #if GDISP_HARDWARE_STREAM_POS
+ priv->x = g->p.x-1; // Make sure these values are invalid (for testing)
+ priv->y = g->p.y-1;
+ #else
+ priv->x = g->p.x;
+ priv->y = g->p.y;
+ #endif
+ g->flags |= GDISP_FLG_WSTREAM;
+ g->flags &= ~GDISP_FLG_WRAPPED;
+ }
+ LLDSPEC void gdisp_lld_write_color(GDisplay *g) {
+ winPriv * priv;
+ int x, y;
+ COLORREF color;
+
+ priv = g->priv;
+ color = COLOR2BGR(g->p.color);
+
+ if (!(g->flags & GDISP_FLG_WSTREAM))
+ BAD_PARAMETER("write_color: not in streaming mode");
+ if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1)
+ BAD_PARAMETER("write_color: cursor outside streaming area");
+ if (g->flags & GDISP_FLG_WRAPPED) {
+ BAD_PARAMETER("write_color: Warning - Area wrapped.");
+ g->flags &= ~GDISP_FLG_WRAPPED;
+ }
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ x = priv->x;
+ y = priv->y;
+ break;
+ case GDISP_ROTATE_90:
+ x = priv->y;
+ y = g->g.Width - 1 - priv->x;
+ break;
+ case GDISP_ROTATE_180:
+ x = g->g.Width - 1 - priv->x;
+ y = g->g.Height - 1 - priv->y;
+ break;
+ case GDISP_ROTATE_270:
+ x = g->g.Height - 1 - priv->y;
+ y = priv->x;
+ break;
+ }
+ #else
+ x = priv->x;
+ y = priv->y;
+ #endif
+
+ // Draw the pixel on the screen and in the buffer.
+ WaitForSingleObject(drawMutex, INFINITE);
+ SetPixel(priv->dcBuffer, x, y, color);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ {
+ RECT r;
+ r.left = x; r.right = x+1;
+ r.top = y; r.bottom = y+1;
+ InvalidateRect(priv->hwnd, &r, FALSE);
+ }
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ SetPixel(dc, x, y, color);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+
+ // Update the cursor
+ if (++priv->x > priv->x1) {
+ priv->x = priv->x0;
+ if (++priv->y > priv->y1) {
+ g->flags |= GDISP_FLG_WRAPPED;
+ priv->y = priv->y0;
+ }
+ }
+ }
+ LLDSPEC void gdisp_lld_write_stop(GDisplay *g) {
+ if (!(g->flags & GDISP_FLG_WSTREAM))
+ BAD_PARAMETER("write_stop: not in streaming mode");
+ g->flags &= ~GDISP_FLG_WSTREAM;
+ }
+ #if GDISP_HARDWARE_STREAM_POS
+ LLDSPEC void gdisp_lld_write_pos(GDisplay *g) {
+ winPriv * priv;
+
+ priv = g->priv;
+
+ if (!(g->flags & GDISP_FLG_WSTREAM))
+ BAD_PARAMETER("write_pos: not in streaming mode");
+ if (g->p.x < priv->x0 || g->p.x > priv->x1 || g->p.y < priv->y0 || g->p.y > priv->y1)
+ BAD_PARAMETER("write_color: new cursor outside streaming area");
+ priv->x = g->p.x;
+ priv->y = g->p.y;
+ }
+ #endif
+#endif
+
+#if GDISP_HARDWARE_STREAM_READ
+ LLDSPEC void gdisp_lld_read_start(GDisplay *g) {
+ winPriv * priv;
+
+ if (g->flags & GDISP_FLG_WSTREAM)
+ BAD_PARAMETER("read_start: already in streaming mode");
+ if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height)
+ BAD_PARAMETER("read_start: bad window parameter");
+
+ priv = g->priv;
+ priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1;
+ priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1;
+ priv->x = g->p.x;
+ priv->y = g->p.y;
+ g->flags |= GDISP_FLG_WSTREAM;
+ g->flags &= ~GDISP_FLG_WRAPPED;
+ }
+ LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) {
+ winPriv * priv;
+ COLORREF color;
+
+ priv = g->priv;
+
+ if (!(g->flags & GDISP_FLG_WSTREAM))
+ BAD_PARAMETER("read_color: not in streaming mode");
+ if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1)
+ BAD_PARAMETER("read_color: cursor outside streaming area");
+ if (g->flags & GDISP_FLG_WRAPPED) {
+ BAD_PARAMETER("read_color: Warning - Area wrapped.");
+ g->flags &= ~GDISP_FLG_WRAPPED;
+ }
+
+ WaitForSingleObject(drawMutex, INFINITE);
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
+ break;
+ case GDISP_ROTATE_90:
+ color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x);
+ break;
+ case GDISP_ROTATE_180:
+ color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y);
+ break;
+ case GDISP_ROTATE_270:
+ color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x);
+ break;
+ }
+ #else
+ color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
+ #endif
+ ReleaseMutex(drawMutex);
+
+ // Update the cursor
+ if (++priv->x > priv->x1) {
+ priv->x = priv->x0;
+ if (++priv->y > priv->y1) {
+ g->flags |= GDISP_FLG_WRAPPED;
+ priv->y = priv->y0;
+ }
+ }
+
+ return BGR2COLOR(color);
+ }
+ LLDSPEC void gdisp_lld_read_stop(GDisplay *g) {
+ if (!(g->flags & GDISP_FLG_WSTREAM))
+ BAD_PARAMETER("write_stop: not in streaming mode");
+ g->flags &= ~GDISP_FLG_WSTREAM;
+ }
+#endif
+
+#if GDISP_HARDWARE_DRAWPIXEL
+ LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
+ winPriv * priv;
+ int x, y;
+ COLORREF color;
+
+ priv = g->priv;
+ color = COLOR2BGR(g->p.color);
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ x = g->p.x;
+ y = g->p.y;
+ break;
+ case GDISP_ROTATE_90:
+ x = g->p.y;
+ y = g->g.Width - 1 - g->p.x;
+ break;
+ case GDISP_ROTATE_180:
+ x = g->g.Width - 1 - g->p.x;
+ y = g->g.Height - 1 - g->p.y;
+ break;
+ case GDISP_ROTATE_270:
+ x = g->g.Height - 1 - g->p.y;
+ y = g->p.x;
+ break;
+ }
+ #else
+ x = g->p.x;
+ y = g->p.y;
+ #endif
+
+ // Draw the pixel on the screen and in the buffer.
+ WaitForSingleObject(drawMutex, INFINITE);
+ SetPixel(priv->dcBuffer, x, y, color);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ {
+ RECT r;
+ r.left = x; r.right = x+1;
+ r.top = y; r.bottom = y+1;
+ InvalidateRect(priv->hwnd, &r, FALSE);
+ }
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ SetPixel(dc, x, y, color);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+ }
+#endif
+
+/* ---- Optional Routines ---- */
+
+#if GDISP_HARDWARE_FILLS
+ LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
+ winPriv * priv;
+ RECT rect;
+ HBRUSH hbr;
+ COLORREF color;
+
+ priv = g->priv;
+ color = COLOR2BGR(g->p.color);
+ hbr = CreateSolidBrush(color);
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ rect.top = g->p.y;
+ rect.bottom = rect.top + g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left + g->p.cx;
+ break;
+ case GDISP_ROTATE_90:
+ rect.bottom = g->g.Width - g->p.x;
+ rect.top = rect.bottom - g->p.cx;
+ rect.left = g->p.y;
+ rect.right = rect.left + g->p.cy;
+ break;
+ case GDISP_ROTATE_180:
+ rect.bottom = g->g.Height - g->p.y;
+ rect.top = rect.bottom - g->p.cy;
+ rect.right = g->g.Width - g->p.x;
+ rect.left = rect.right - g->p.cx;
+ break;
+ case GDISP_ROTATE_270:
+ rect.top = g->p.x;
+ rect.bottom = rect.top + g->p.cx;
+ rect.right = g->g.Height - g->p.y;
+ rect.left = rect.right - g->p.cy;
+ break;
+ }
+ #else
+ rect.top = g->p.y;
+ rect.bottom = rect.top + g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left + g->p.cx;
+ #endif
+
+
+ WaitForSingleObject(drawMutex, INFINITE);
+ FillRect(priv->dcBuffer, &rect, hbr);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ InvalidateRect(priv->hwnd, &rect, FALSE);
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ FillRect(dc, &rect, hbr);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+
+ DeleteObject(hbr);
+ }
+#endif
+
+#if GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL
+ static pixel_t *rotateimg(GDisplay *g, const pixel_t *buffer) {
+ pixel_t *dstbuf;
+ pixel_t *dst;
+ const pixel_t *src;
+ size_t sz;
+ coord_t i, j;
+
+ // Allocate the destination buffer
+ sz = (size_t)g->p.cx * (size_t)g->p.cy;
+ if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t))))
+ return 0;
+
+ // Copy the bits we need
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ return 0; // not handled as it doesn't need to be.
+ case GDISP_ROTATE_90:
+ for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) {
+ dst = dstbuf+sz-g->p.cy+j;
+ for(i = 0; i < g->p.cx; i++, dst -= g->p.cy)
+ *dst = *src++;
+ }
+ break;
+ case GDISP_ROTATE_180:
+ for(dst = dstbuf+sz, src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx)
+ for(i = 0; i < g->p.cx; i++)
+ *--dst = *src++;
+ break;
+ case GDISP_ROTATE_270:
+ for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) {
+ dst = dstbuf+g->p.cy-j-1;
+ for(i = 0; i < g->p.cx; i++, dst += g->p.cy)
+ *dst = *src++;
+ }
+ break;
+ }
+ return dstbuf;
+ }
+#endif
+
+#if GDISP_HARDWARE_BITFILLS
+ LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
+ winPriv * priv;
+ pixel_t * buffer;
+ RECT rect;
+ BITMAPV4HEADER bmpInfo;
+
+ // Make everything relative to the start of the line
+ priv = g->priv;
+ buffer = g->p.ptr;
+ buffer += g->p.x2*g->p.y1;
+
+ memset(&bmpInfo, 0, sizeof(bmpInfo));
+ bmpInfo.bV4Size = sizeof(bmpInfo);
+ bmpInfo.bV4Planes = 1;
+ bmpInfo.bV4BitCount = sizeof(pixel_t)*8;
+ bmpInfo.bV4AlphaMask = 0;
+ bmpInfo.bV4RedMask = RGB2COLOR(255,0,0);
+ bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0);
+ bmpInfo.bV4BlueMask = RGB2COLOR(0,0,255);
+ bmpInfo.bV4V4Compression = BI_BITFIELDS;
+ bmpInfo.bV4XPelsPerMeter = 3078;
+ bmpInfo.bV4YPelsPerMeter = 3078;
+ bmpInfo.bV4ClrUsed = 0;
+ bmpInfo.bV4ClrImportant = 0;
+ bmpInfo.bV4CSType = 0; //LCS_sRGB;
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t);
+ bmpInfo.bV4Width = g->p.x2;
+ bmpInfo.bV4Height = -g->p.cy; /* top-down image */
+ rect.top = g->p.y;
+ rect.bottom = rect.top+g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left+g->p.cx;
+ break;
+ case GDISP_ROTATE_90:
+ if (!(buffer = rotateimg(g, buffer))) return;
+ bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t);
+ bmpInfo.bV4Width = g->p.cy;
+ bmpInfo.bV4Height = -g->p.cx; /* top-down image */
+ rect.bottom = g->g.Width - g->p.x;
+ rect.top = rect.bottom-g->p.cx;
+ rect.left = g->p.y;
+ rect.right = rect.left+g->p.cy;
+ break;
+ case GDISP_ROTATE_180:
+ if (!(buffer = rotateimg(g, buffer))) return;
+ bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t);
+ bmpInfo.bV4Width = g->p.cx;
+ bmpInfo.bV4Height = -g->p.cy; /* top-down image */
+ rect.bottom = g->g.Height-1 - g->p.y;
+ rect.top = rect.bottom-g->p.cy;
+ rect.right = g->g.Width - g->p.x;
+ rect.left = rect.right-g->p.cx;
+ break;
+ case GDISP_ROTATE_270:
+ if (!(buffer = rotateimg(g, buffer))) return;
+ bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t);
+ bmpInfo.bV4Width = g->p.cy;
+ bmpInfo.bV4Height = -g->p.cx; /* top-down image */
+ rect.top = g->p.x;
+ rect.bottom = rect.top+g->p.cx;
+ rect.right = g->g.Height - g->p.y;
+ rect.left = rect.right-g->p.cy;
+ break;
+ }
+ #else
+ bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t);
+ bmpInfo.bV4Width = g->p.x2;
+ bmpInfo.bV4Height = -g->p.cy; /* top-down image */
+ rect.top = g->p.y;
+ rect.bottom = rect.top+g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left+g->p.cx;
+ #endif
+
+ WaitForSingleObject(drawMutex, INFINITE);
+ SetDIBitsToDevice(priv->dcBuffer, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ InvalidateRect(priv->hwnd, &rect, FALSE);
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ SetDIBitsToDevice(dc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+
+ #if GDISP_NEED_CONTROL
+ if (buffer != (pixel_t *)g->p.ptr)
+ free(buffer);
+ #endif
+ }
+#endif
+
+#if GDISP_HARDWARE_PIXELREAD
+ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
+ winPriv * priv;
+ COLORREF color;
+
+ priv = g->priv;
+
+ WaitForSingleObject(drawMutex, INFINITE);
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
+ break;
+ case GDISP_ROTATE_90:
+ color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x);
+ break;
+ case GDISP_ROTATE_180:
+ color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y);
+ break;
+ case GDISP_ROTATE_270:
+ color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x);
+ break;
+ }
+ #else
+ color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
+ #endif
+ ReleaseMutex(drawMutex);
+
+ return BGR2COLOR(color);
+ }
+#endif
+
+#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
+ LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) {
+ winPriv * priv;
+ RECT rect;
+ coord_t lines;
+
+ priv = g->priv;
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ rect.top = g->p.y;
+ rect.bottom = rect.top+g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left+g->p.cx;
+ lines = -g->p.y1;
+ goto vertical_scroll;
+ case GDISP_ROTATE_90:
+ rect.bottom = g->g.Width - g->p.x;
+ rect.top = rect.bottom-g->p.cx;
+ rect.left = g->p.y;
+ rect.right = rect.left+g->p.cy;
+ lines = -g->p.y1;
+ goto horizontal_scroll;
+ case GDISP_ROTATE_180:
+ rect.bottom = g->g.Height - g->p.y;
+ rect.top = rect.bottom-g->p.cy;
+ rect.right = g->g.Width - g->p.x;
+ rect.left = rect.right-g->p.cx;
+ lines = g->p.y1;
+ vertical_scroll:
+ if (lines > 0) {
+ rect.bottom -= lines;
+ } else {
+ rect.top -= lines;
+ }
+ if (g->p.cy >= lines && g->p.cy >= -lines) {
+ WaitForSingleObject(drawMutex, INFINITE);
+ ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ InvalidateRect(priv->hwnd, &rect, FALSE);
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ ScrollDC(dc, 0, lines, &rect, 0, 0, 0);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+ }
+ break;
+ case GDISP_ROTATE_270:
+ rect.top = g->p.x;
+ rect.bottom = rect.top+g->p.cx;
+ rect.right = g->g.Height - g->p.y;
+ rect.left = rect.right-g->p.cy;
+ lines = g->p.y1;
+ horizontal_scroll:
+ if (lines > 0) {
+ rect.right -= lines;
+ } else {
+ rect.left -= lines;
+ }
+ if (g->p.cy >= lines && g->p.cy >= -lines) {
+ WaitForSingleObject(drawMutex, INFINITE);
+ ScrollDC(priv->dcBuffer, lines, 0, &rect, 0, 0, 0);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ InvalidateRect(priv->hwnd, &rect, FALSE);
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ ScrollDC(dc, lines, 0, &rect, 0, 0, 0);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+ }
+ break;
+ }
+ #else
+ rect.top = g->p.y;
+ rect.bottom = rect.top+g->p.cy;
+ rect.left = g->p.x;
+ rect.right = rect.left+g->p.cx;
+ lines = -g->p.y1;
+ if (lines > 0) {
+ rect.bottom -= lines;
+ } else {
+ rect.top -= lines;
+ }
+ if (g->p.cy >= lines && g->p.cy >= -lines) {
+ WaitForSingleObject(drawMutex, INFINITE);
+ ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0);
+ #if GDISP_WIN32_USE_INDIRECT_UPDATE
+ ReleaseMutex(drawMutex);
+ InvalidateRect(priv->hwnd, &rect, FALSE);
+ #else
+ {
+ HDC dc;
+ dc = GetDC(priv->hwnd);
+ ScrollDC(dc, 0, lines, &rect, 0, 0, 0);
+ ReleaseDC(priv->hwnd, dc);
+ ReleaseMutex(drawMutex);
+ }
+ #endif
+ }
+ #endif
+ }
+#endif
+
+#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay *g) {
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ return;
+/*
+ case GDISP_CONTROL_POWER:
+ case GDISP_CONTROL_BACKLIGHT:
+ case GDISP_CONTROL_CONTRAST:
+*/
+ }
+ }
+#endif
+
+#if GINPUT_NEED_MOUSE
+ void ginput_lld_mouse_init(void) {}
+ void ginput_lld_mouse_get_reading(MouseReading *pt) {
+ GDisplay * g;
+ winPriv * priv;
+
+ g = mouseDisplay;
+ priv = g->priv;
+
+ pt->x = priv->mousex;
+ pt->y = priv->mousey > g->g.Height ? g->g.Height : priv->mousey;
+ pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0;
+ pt->buttons = priv->mousebuttons;
+ }
+#endif /* GINPUT_NEED_MOUSE */
+
+#if GINPUT_NEED_TOGGLE
+ #if GINPUT_TOGGLE_CONFIG_ENTRIES > GDISP_DRIVER_COUNT_WIN32
+ #error "GDISP Win32: GINPUT_TOGGLE_CONFIG_ENTRIES must not be greater than GDISP_DRIVER_COUNT_WIN32"
+ #endif
+
+ GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES];
+
+ void ginput_lld_toggle_init(const GToggleConfig *ptc) {
+ // Save the associated window struct
+ ptc->id = &GDISP_WIN32[ptc - GInputToggleConfigTable];
+
+ // We have 8 buttons per window.
+ ptc->mask = 0xFF;
+
+ // No inverse or special mode
+ ptc->invert = 0x00;
+ ptc->mode = 0;
+ }
+ unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) {
+ return ((GDisplay *)(ptc->id))->priv->toggles;
+ }
+#endif /* GINPUT_NEED_TOGGLE */
+
+#endif /* GFX_USE_GDISP */
+