You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
ndg/x11/x11.c

282 lines
7.9 KiB
C

Squashed 'lib/lv_drivers/' changes from 718302577..0091dc612 0091dc612 fix(wayland): fix compile error wrt LV_WAYLAND_CLIENT_SIDE_DECORATIONS (#307) 451e659cf Add pkgconfig file (#301) 5a5b4a1a3 added x11 display driver port (#300) 4391dbf32 perf(drm): use wait_cb for direct double-buffered rendering (#299) 7e18481ce fix(drm): backport drm driver fixes from lvgl 9 (#298) f5b58b947 feat(evdev): backport multi device support from lvgl 9 (#296) ad66ff155 add return value to drm_init c239cc465 Removed clamp from Calibrate section as it has map in it e44e7f043 fix(build): Update xpt2046_read to match signature required by lv_indev_drv_t's read callback. (#290) 7b9dee11c Fix crash during startup in certain conditions (#286) 9d153fb65 Add USE_WAYLAND to smm.c (#285) 8669c6fc8 libInput: Add POINTER_MOTION_ABSOLUTE support (#284) c71e5f84b drm: Default to XRGB8888 framebuffer (#282) 57494ff8e Add a way to set SDL window title from lv_drv_conf.h (#277) b03c9dac9 fix(xkb): Fix memory leak by avoiding double reference (#276) ec0ad8296 feature(libinput): Expose function for querying capability (#275) 0d5de84e2 feature(libinput): Add function to reset driver states (#274) 94dc4ce06 Use win32 singly linked list instead of LVGL linked list for fixing memory access conflict issues for win32drv. (#273) 1792ab20a feature(wayland): add a shared memory manager, allowing backing buffers to be allocated on demand. (#270) f7935569f use SDL_RES instead of LV_RES for touch events (#268) ba9c3cc4f Update README.md (#261) f261225d9 follow lvgl changes ab5e30ccb Add the multiple display support for win32drv. (#259) 820341ea1 Improve the keyboard support for win32drv. (#258) b13361a1f fix: The mouse moves outside the screen area (#251) 829e0ffc3 chore(wayland) : accelerate damage updates, reduce unnecessary cycles (#249) 5523f9974 fix(wayland-protocols): minimum version (#246) fe9de86e9 Wayland api fixes (#243) 59e698ce1 fix(wayland) : fix possible memory leak (#238) 2ed01feab fix(drm): Fix compiler warnings (#237) cf4e6d75a make windows.h lower case (#236) dc0d71a3a chore(sdl): fix warning (#232) c68b59e42 fix(fbdev): Fix rendering for 24 bits per pixel (#231) 4f98fddd2 hide the SDL2 include from public LVGL functions (#227) ff01834db fix(fbdev): Gracefully handle FBIOBLANK errors (#229) 73219786a bump version number to v9.0.0-dev git-subtree-dir: lib/lv_drivers git-subtree-split: 0091dc612facc94dce1061a9b78d641c77f1791a
7 months ago
/**
* @file x11.c
*
*/
/*********************
* INCLUDES
*********************/
#include "x11.h"
#if USE_X11
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
/*********************
* DEFINES
*********************/
#ifndef KEYBOARD_BUFFER_SIZE
#define KEYBOARD_BUFFER_SIZE 64
#endif
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#ifndef X11_OPTIMIZED_SCREEN_UPDATE
#define X11_OPTIMIZED_SCREEN_UPDATE 1
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC VARIABLES
**********************/
static Display* display = NULL;
static Window window = (XID)-1;
static GC gc = NULL;
static XImage* ximage = NULL;
static lv_timer_t* timer = NULL;
static char kb_buffer[KEYBOARD_BUFFER_SIZE];
static lv_point_t mouse_pos = { 0, 0 };
static bool left_mouse_btn = false;
static bool right_mouse_btn = false;
static bool wheel_mouse_btn = false;
static int16_t wheel_cnt = 0;
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
static int predicate(Display* disp, XEvent* evt, XPointer arg) { return 1; }
static void x11_event_handler(lv_timer_t * t)
{
XEvent myevent;
KeySym mykey;
int n;
/* handle all outstanding X events */
while (XCheckIfEvent(display, &myevent, predicate, NULL)) {
switch(myevent.type)
{
case Expose:
if(myevent.xexpose.count==0)
{
XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES);
}
break;
case MotionNotify:
mouse_pos.x = myevent.xmotion.x;
mouse_pos.y = myevent.xmotion.y;
break;
case ButtonPress:
switch (myevent.xbutton.button)
{
case Button1:
left_mouse_btn = true;
break;
case Button2:
wheel_mouse_btn = true;
break;
case Button3:
right_mouse_btn = true;
break;
case Button4:
wheel_cnt--; // Scrolled up
break;
case Button5:
wheel_cnt++; // Scrolled down
break;
default:
LV_LOG_WARN("unhandled button press : %d", myevent.xbutton.button);
}
break;
case ButtonRelease:
switch (myevent.xbutton.button)
{
case Button1:
left_mouse_btn = false;
break;
case Button2:
wheel_mouse_btn = false;
break;
case Button3:
right_mouse_btn = false;
break;
}
break;
case KeyPress:
n = XLookupString(&myevent.xkey, &kb_buffer[0], sizeof(kb_buffer), &mykey, NULL);
kb_buffer[n] = '\0';
break;
case KeyRelease:
break;
default:
LV_LOG_WARN("unhandled x11 event: %d", myevent.type);
}
}
}
static void lv_x11_hide_cursor()
{
XColor black = { .red = 0, .green = 0, .blue = 0 };
char empty_data[] = { 0 };
Pixmap empty_bitmap = XCreateBitmapFromData(display, window, empty_data, 1, 1);
Cursor inv_cursor = XCreatePixmapCursor(display, empty_bitmap, empty_bitmap, &black, &black, 0, 0);
XDefineCursor(display, window, inv_cursor);
XFreeCursor(display, inv_cursor);
XFreePixmap(display, empty_bitmap);
}
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_x11_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
#if X11_OPTIMIZED_SCREEN_UPDATE
static const lv_area_t inv_area = { .x1 = 0xFFFF,
.x2 = 0,
.y1 = 0xFFFF,
.y2 = 0
};
static lv_area_t upd_area = inv_area;
/* build display update area until lv_disp_flush_is_last */
upd_area.x1 = MIN(upd_area.x1, area->x1);
upd_area.x2 = MAX(upd_area.x2, area->x2);
upd_area.y1 = MIN(upd_area.y1, area->y1);
upd_area.y2 = MAX(upd_area.y2, area->y2);
#endif // X11_OPTIMIZED_SCREEN_UPDATE
for (lv_coord_t y = area->y1; y <= area->y2; y++)
{
uint32_t dst_offs = area->x1 + y * LV_HOR_RES;
uint32_t* dst_data = &((uint32_t*)ximage->data)[dst_offs];
for (lv_coord_t x = area->x1; x <= area->x2; x++, color_p++, dst_data++)
{
*dst_data = lv_color_to32(*color_p);
}
}
if (lv_disp_flush_is_last(disp_drv))
{
#if X11_OPTIMIZED_SCREEN_UPDATE
/* refresh collected display update area only */
lv_coord_t upd_w = upd_area.x2 - upd_area.x1 + 1;
lv_coord_t upd_h = upd_area.y2 - upd_area.y1 + 1;
XPutImage(display, window, gc, ximage, upd_area.x1, upd_area.y1, upd_area.x1, upd_area.y1, upd_w, upd_h);
/* invalidate collected area */
upd_area = inv_area;
#else
/* refresh full display */
XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES);
#endif
}
lv_disp_flush_ready(disp_drv);
}
void lv_x11_get_pointer(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
data->point = mouse_pos;
data->state = left_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
void lv_x11_get_mousewheel(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
data->state = wheel_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
data->enc_diff = wheel_cnt;
wheel_cnt = 0;
}
void lv_x11_get_keyboard(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
size_t len = strlen(kb_buffer);
if (len > 0)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = kb_buffer[0];
memmove(kb_buffer, kb_buffer + 1, len);
data->continue_reading = (len > 0);
}
else
{
data->state = LV_INDEV_STATE_RELEASED;
}
}
void lv_x11_init(char const* title, lv_coord_t width, lv_coord_t height)
{
/* setup display/screen */
display = XOpenDisplay(NULL);
int screen = DefaultScreen(display);
/* drawing contexts for an window */
unsigned long myforeground = BlackPixel(display, screen);
unsigned long mybackground = WhitePixel(display, screen);
/* create window */
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
0, 0, width, height,
0, myforeground, mybackground);
/* window manager properties (yes, use of StdProp is obsolete) */
XSetStandardProperties(display, window, title, NULL, None, NULL, 0, NULL);
/* allow receiving mouse and keyboard events */
XSelectInput(display, window, PointerMotionMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask|ExposureMask);
/* graphics context */
gc = XCreateGC(display, window, 0, 0);
lv_x11_hide_cursor();
/* create cache XImage */
Visual* visual = XDefaultVisual(display, screen);
int dplanes = DisplayPlanes(display, screen);
ximage = XCreateImage(display, visual, dplanes, ZPixmap, 0,
malloc(width * height * sizeof(uint32_t)), width, height, 32, 0);
timer = lv_timer_create(x11_event_handler, 10, NULL);
/* finally bring window on top of the other windows */
XMapRaised(display, window);
}
void lv_x11_deinit(void)
{
lv_timer_del(timer);
free(ximage->data);
XDestroyImage(ximage);
ximage = NULL;
XFreeGC(display, gc);
gc = NULL;
XDestroyWindow(display, window);
window = (XID)-1;
XCloseDisplay(display);
display = NULL;
}
#endif // USE_X11