x11 implementation

This commit is contained in:
Thomas Bernard 2018-06-26 17:30:16 +02:00
parent a514f7e9a2
commit 77f36a1f8e
6 changed files with 559 additions and 0 deletions

View File

@ -586,6 +586,11 @@ endif
ifeq ($(API),win32)
APIOBJ = win32screen.o
endif
ifeq ($(API),x11)
APIOBJ = x11screen.o
COPT += -DUSE_X11
LOPT += -lX11
endif
#To enable Joystick emulation of cursor, make USE_JOYSTICK=1 (for input.o)
#This can be necessary to test cursor code on a PC, but by default for all

View File

@ -31,6 +31,13 @@
#include <shellapi.h>
#endif
#ifdef USE_X11
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/Xutil.h>
#endif
#include "global.h"
#include "keyboard.h"
#include "screen.h"
@ -41,6 +48,9 @@
#include "input.h"
#include "loadsave.h"
#ifdef USE_X11
extern Display * X11_display;
#endif
#if defined(USE_SDL)
#define RSUPER_EMULATES_META_MOD
@ -1215,6 +1225,146 @@ int Get_input(int sleep_time)
WaitMessage();
KillTimer(NULL, timerId);
}
#elif defined(USE_X11)
int user_feedback_required = 0; // Flag qui indique si on doit arrêter de traiter les évènements ou si on peut enchainer
Color_cycling();
// Commit any pending screen update.
// This is done in this function because it's called after reading
// some user input.
Flush_update();
Key_ANSI = 0;
Key_UNICODE = 0;
Key = 0;
Mouse_moved=0;
Input_new_mouse_X = Mouse_X;
Input_new_mouse_Y = Mouse_Y;
Input_new_mouse_K = Mouse_K;
XFlush(X11_display);
while(!user_feedback_required && XPending(X11_display) > 0)
{
word mod = 0;
XEvent event;
XNextEvent(X11_display, &event);
switch(event.type)
{
case KeyPress:
{
KeySym sym;
//printf("key code = %d state=0x%08x\n", event.xkey.keycode, event.xkey.state);
// right/left window 40 Mod4Mask
// left alt = 8 Mod1Mask
// right alt = 80 Mod5Mask
// NumLock = 10 Mod2Mask
if (event.xkey.state & ShiftMask)
mod |= MOD_SHIFT;
if (event.xkey.state & ControlMask)
mod |= MOD_CTRL;
if (event.xkey.state & (Mod1Mask | Mod5Mask))
mod |= MOD_ALT;
if (event.xkey.state & Mod3Mask)
mod |= MOD_META;
//sym = XKeycodeToKeysym(X11_display, event.xkey.keycode, 0);
sym = XkbKeycodeToKeysym(X11_display, event.xkey.keycode, 0, 0);
//printf("sym = %04lx %s\t\tmod=%04x\n", sym, XKeysymToString(sym), mod);
Key = mod | (sym & 0x0fff);
//sym = XkbKeycodeToKeysym(X11_display, event.xkey.keycode, 0, event.xkey.state);
if ((sym & 0xf000) != 0xf000) // test for standard key
{
int count;
char buffer[16];
static XComposeStatus status;
count = XLookupString(&event.xkey, buffer, sizeof(buffer),
&sym, &status);
//printf(" sym = %04lx %s %d %s\n", sym, XKeysymToString(sym), count, buffer);
Key_UNICODE = sym;
if (sym < 0x100)
Key_ANSI = sym;
}
user_feedback_required = 1;
}
break;
case ButtonPress: // left = 1, middle = 2, right = 3, wheelup = 4, wheeldown = 5
//printf("Press button = %d state = 0x%08x\n", event.xbutton.button, event.xbutton.state);
if (event.xkey.state & ShiftMask)
mod |= MOD_SHIFT;
if (event.xkey.state & ControlMask)
mod |= MOD_CTRL;
if (event.xkey.state & (Mod1Mask | Mod5Mask))
mod |= MOD_ALT;
if (event.xkey.state & Mod3Mask)
mod |= MOD_META;
switch(event.xbutton.button)
{
case 1:
case 3:
{
byte mask = 1;
if(event.xbutton.button == 3)
mask ^= 3;
if (Button_inverter)
mask ^= 3;
Input_new_mouse_K |= mask;
user_feedback_required = Move_cursor_with_constraints();
}
break;
case 2:
Key = KEY_MOUSEMIDDLE | mod;
user_feedback_required = 1;
break;
case 4:
Key = KEY_MOUSEWHEELUP | mod;
user_feedback_required = 1;
break;
case 5:
Key = KEY_MOUSEWHEELDOWN | mod;
user_feedback_required = 1;
break;
}
break;
case ButtonRelease:
//printf("Release button = %d\n", event.xbutton.button);
if(event.xbutton.button == 1 || event.xbutton.button == 3)
{
byte mask = 1;
if(event.xbutton.button == 3)
mask ^= 3;
if (Button_inverter)
mask ^= 3;
Input_new_mouse_K &= ~mask;
user_feedback_required = Move_cursor_with_constraints();
}
break;
case MotionNotify:
//printf("mouse %dx%d\n", event.xmotion.x, event.xmotion.y);
Input_new_mouse_X = (event.xmotion.x < 0) ? 0 : event.xmotion.x/Pixel_width;
Input_new_mouse_Y = (event.xmotion.y < 0) ? 0 : event.xmotion.y/Pixel_height;
user_feedback_required = Move_cursor_with_constraints();
break;
case Expose:
printf("Expose (%d,%d) (%d,%d)\n", event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height);
Update_rect(event.xexpose.x, event.xexpose.y,
event.xexpose.width, event.xexpose.height);
break;
default:
printf("event.type = %d\n", event.type);
}
}
// If the cursor was moved since last update,
// it was erased, so we need to redraw it (with the preview brush)
if (Mouse_moved)
{
Compute_paintbrush_coordinates();
Display_cursor();
return 1;
}
if (user_feedback_required)
return 1;
// Nothing significant happened
if (sleep_time)
usleep(1000 * sleep_time);
#endif
return 0;
}

View File

@ -810,12 +810,14 @@ word Key_for_scancode(word scancode)
word Get_Key_modifiers(void)
{
word mod = 0;
#if defined(WIN32)
if (GetKeyState(VK_SHIFT) & 0x8000)
mod |= MOD_SHIFT;
if (GetKeyState(VK_CONTROL) & 0x8000)
mod |= MOD_CTRL;
if (GetKeyState(VK_MENU) & 0x8000)
mod |= MOD_ALT;
#endif
return mod;
}
#endif

View File

@ -26,12 +26,16 @@
#include <SDL.h>
#elif defined(WIN32)
#include <windows.h>
#elif defined(USE_X11)
#include <X11/keysym.h>
#endif
#if defined(USE_SDL)
#define K2K(x) (x)
#elif defined(USE_SDL2)
#define K2K(x) ((((x) & 0x40000000) >> 19) | ((x) & 0x1FF))
#elif defined(USE_X11)
#define K2K(x) ((x) & 0x0FFF)
#endif
/* generated lists */
@ -150,6 +154,107 @@
#define KEY_F11 K2K(SDLK_F11)
#define KEY_F12 K2K(SDLK_F12)
// end of KEY definitions for SDL and SDL2
#elif defined(USE_X11)
// KEY definitions for x11
#define KEY_UNKNOWN 0
#define KEY_ESCAPE K2K(XK_Escape)
#define KEY_RETURN K2K(XK_Return)
#define KEY_BACKSPACE K2K(XK_BackSpace)
#define KEY_TAB K2K(XK_Tab)
#define KEY_UP K2K(XK_Up)
#define KEY_DOWN K2K(XK_Down)
#define KEY_LEFT K2K(XK_Left)
#define KEY_RIGHT K2K(XK_Right)
#define KEY_LEFTBRACKET K2K(XK_bracketleft)
#define KEY_RIGHTBRACKET K2K(XK_bracketright)
#define KEY_INSERT K2K(XK_Insert)
#define KEY_DELETE K2K(XK_Delete)
#define KEY_COMMA K2K(XK_comma)
#define KEY_BACKQUOTE K2K(XK_grave)
#define KEY_PAGEUP K2K(XK_Page_Up)
#define KEY_PAGEDOWN K2K(XK_Page_Down)
#define KEY_HOME K2K(XK_Home)
#define KEY_END K2K(XK_End)
#define KEY_KP_PLUS K2K(XK_KP_Add)
#define KEY_KP_MINUS K2K(XK_KP_Subtract)
#define KEY_KP_MULTIPLY K2K(XK_KP_Multiply)
#define KEY_KP_ENTER K2K(XK_KP_Enter)
#define KEY_KP_DIVIDE K2K(XK_KP_Divide)
#define KEY_KP_PERIOD K2K(XK_KP_Decimal)
#define KEY_KP_EQUALS K2K(XK_KP_Equal)
#define KEY_EQUALS K2K(XK_equal)
#define KEY_MINUS K2K(XK_minus)
#define KEY_PERIOD K2K(XK_period)
#define KEY_CAPSLOCK K2K(XK_Caps_Lock)
#define KEY_CLEAR K2K(XK_Clear)
#define KEY_SPACE K2K(XK_space)
#define KEY_PAUSE K2K(XK_Pause)
#define KEY_LSHIFT K2K(XK_Shift_L)
#define KEY_RSHIFT K2K(XK_Shift_R)
#define KEY_LCTRL K2K(XK_Control_L)
#define KEY_RCTRL K2K(XK_Control_R)
#define KEY_LALT K2K(XK_Alt_L)
#define KEY_RALT K2K(XK_Alt_R)
#define KEY_0 K2K(XK_0)
#define KEY_1 K2K(XK_1)
#define KEY_2 K2K(XK_2)
#define KEY_3 K2K(XK_3)
#define KEY_4 K2K(XK_4)
#define KEY_5 K2K(XK_5)
#define KEY_6 K2K(XK_6)
#define KEY_7 K2K(XK_7)
#define KEY_8 K2K(XK_8)
#define KEY_9 K2K(XK_9)
#define KEY_a K2K(XK_a)
#define KEY_b K2K(XK_b)
#define KEY_c K2K(XK_c)
#define KEY_d K2K(XK_d)
#define KEY_e K2K(XK_e)
#define KEY_f K2K(XK_f)
#define KEY_g K2K(XK_g)
#define KEY_h K2K(XK_h)
#define KEY_i K2K(XK_i)
#define KEY_j K2K(XK_j)
#define KEY_k K2K(XK_k)
#define KEY_l K2K(XK_l)
#define KEY_m K2K(XK_m)
#define KEY_n K2K(XK_n)
#define KEY_o K2K(XK_o)
#define KEY_p K2K(XK_p)
#define KEY_q K2K(XK_q)
#define KEY_r K2K(XK_r)
#define KEY_s K2K(XK_s)
#define KEY_t K2K(XK_t)
#define KEY_u K2K(XK_u)
#define KEY_v K2K(XK_v)
#define KEY_w K2K(XK_w)
#define KEY_x K2K(XK_x)
#define KEY_y K2K(XK_y)
#define KEY_z K2K(XK_z)
#define KEY_KP0 K2K(XK_KP_0)
#define KEY_KP1 K2K(XK_KP_1)
#define KEY_KP2 K2K(XK_KP_2)
#define KEY_KP3 K2K(XK_KP_3)
#define KEY_KP4 K2K(XK_KP_4)
#define KEY_KP5 K2K(XK_KP_5)
#define KEY_KP6 K2K(XK_KP_6)
#define KEY_KP7 K2K(XK_KP_7)
#define KEY_KP8 K2K(XK_KP_8)
#define KEY_KP9 K2K(XK_KP_9)
#define KEY_SCROLLOCK K2K(XK_Scroll_Lock)
#define KEY_F1 K2K(XK_F1)
#define KEY_F2 K2K(XK_F2)
#define KEY_F3 K2K(XK_F3)
#define KEY_F4 K2K(XK_F4)
#define KEY_F5 K2K(XK_F5)
#define KEY_F6 K2K(XK_F6)
#define KEY_F7 K2K(XK_F7)
#define KEY_F8 K2K(XK_F8)
#define KEY_F9 K2K(XK_F9)
#define KEY_F10 K2K(XK_F10)
#define KEY_F11 K2K(XK_F11)
#define KEY_F12 K2K(XK_F12)
// end of KEY definitions for x11
#elif defined(WIN32)
// KEY definitions for win32
#define KEY_UNKNOWN 0

256
src/x11screen.c Normal file
View File

@ -0,0 +1,256 @@
/* vim:expandtab:ts=2 sw=2:
*/
/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2018 Thomas Bernard
Copyright 2008 Yves Rizoud
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see <http://www.gnu.org/licenses/>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "screen.h"
#include "gfx2surface.h"
Display * X11_display = NULL;
static Window X11_window = 0;
static XImage * X11_image = NULL;
static char * image_pixels = NULL;
static XTextProperty windowName;
static GC X11_gc = 0;
static T_GFX2_Surface * screen = NULL;
void GFX2_Set_mode(int *width, int *height, int fullscreen)
{
int s;
int depth;
unsigned long white, black;
char * winName[] = { "GrafX2" };
Visual * visual;
const char blank_data[1] = { 0 };
Pixmap blank;
Cursor cursor;
XColor dummy;
if (X11_display == NULL)
X11_display = XOpenDisplay(NULL);//getenv("DISPLAY")
if (X11_display == NULL)
{
fprintf(stderr, "X11: cannot open display\n");
exit(1);
}
s = DefaultScreen(X11_display);
black = BlackPixel(X11_display, s);
white = WhitePixel(X11_display, s);
visual = DefaultVisual(X11_display, s);
{
int i;
int count = 0;
int * depths = XListDepths(X11_display, s, &count);
printf("DefaultDepth = %d, DisplayPlanes = %d\n", DefaultDepth(X11_display, s), DisplayPlanes(X11_display, s));
if (depths != NULL)
{
for (i = 0; i < count; i++)
printf(" %d", depths[i]);
printf("\n");
XFree(depths);
}
}
depth = DisplayPlanes(X11_display, s);
X11_window = XCreateSimpleWindow(X11_display, RootWindow(X11_display, s),
0, 0, *width, *height, 0, white, black);
// create blank 1x1 pixmap to make a 1x1 transparent cursor
blank = XCreateBitmapFromData(X11_display, X11_window, blank_data, 1, 1);
cursor = XCreatePixmapCursor(X11_display, blank, blank, &dummy, &dummy, 0, 0);
//cursor = XCreateFontCursor(X11_display, 130 /*XC_tcross*/);
XDefineCursor(X11_display, X11_window, cursor);
XFreePixmap(X11_display, blank);
XFreeCursor(X11_display, cursor);
X11_gc = XCreateGC(X11_display, X11_window, 0, NULL);
XSetFunction(X11_display, X11_gc, GXcopy);
XStringListToTextProperty(winName, 1, &windowName);
XSetWMName(X11_display, X11_window, &windowName);
// TODO : set icon
screen = New_GFX2_Surface(*width, *height);
memset(screen->pixels, 0, *width * *height);
image_pixels = malloc(*height * *width * 4);
memset(image_pixels, 64, *height * *width * 4);
#if 0
{
int i;
for (i= 3*8; i < (*height * *width * 4); i += *width * 4)
{
image_pixels[i+0] = 0; // B
image_pixels[i+1] = 0; // G
image_pixels[i+2] = 0; // R
}
}
#endif
X11_image = XCreateImage(X11_display, visual, depth,
ZPixmap, 0, image_pixels, *width, *height,
32, 0/**width * 4*/);
if(X11_image == NULL)
{
fprintf(stderr, "XCreateImage failed\n");
exit(1);
}
XSelectInput(X11_display, X11_window,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | ExposureMask | StructureNotifyMask);
XMapWindow(X11_display, X11_window);
XFlush(X11_display);
}
byte Get_Screen_pixel(int x, int y)
{
if(screen == NULL) return 0;
return screen->pixels[x + y * screen->w];
}
void Set_Screen_pixel(int x, int y, byte value)
{
if(screen == NULL) return;
screen->pixels[x + y * screen->w] = value;
}
byte* Get_Screen_pixel_ptr(int x, int y)
{
if(screen == NULL) return NULL;
return screen->pixels + x + y * screen->w;
}
void Screen_FillRect(int x, int y, int w, int h, byte color)
{
int i;
byte * ptr;
if (x < 0)
{
w += x;
x = 0;
}
if (y < 0)
{
h += y;
y = 0;
}
if (x > screen->w || y > screen->h)
return;
if ((x + w) > screen->w)
w = screen->w - x;
if ((y + h) > screen->h)
h = screen->h - y;
if (w <= 0 || h <= 0)
return;
for (i = 0; i < h; i++)
{
ptr = Get_Screen_pixel_ptr(x, y + i);
memset(ptr, color, w);
}
}
int SetPalette(const T_Components * colors, int firstcolor, int ncolors)
{
if (screen == NULL) return 0;
memcpy(screen->palette + firstcolor, colors, ncolors * sizeof(T_Components));
return 1;
}
void Update_rect(short x, short y, unsigned short width, unsigned short height)
{
int line, i;
if (screen == NULL || X11_image == NULL) return;
x *= Pixel_width;
width *= Pixel_width;
y *= Pixel_height;
height *= Pixel_height;
//printf("Update_rect(%d %d %d %d) %d %d\n", x, y, width, height, screen->w, screen->h);
if (y >= screen->h || x >= screen->w) return;
if (y + height > screen->h)
height = screen->h - y;
if (x + width > screen->w)
width = screen->w - x;
for (line = y; line < y + height; line++)
{
#if 0
const byte * src = Get_Screen_pixel_ptr(x, line);
byte * dest = image_pixels + line * X11_image->bytes_per_line + x * 4,
i = width;
do
{
dest[0] = screen->palette[*src].B;
dest[1] = screen->palette[*src].G;
dest[2] = screen->palette[*src].R;
dest[3] = 0;
src++;
dest += 4;
}
while(--i > 0);
#else
for (i = 0; i < width; i++)
{
byte v = Get_Screen_pixel(x + i, line);
XPutPixel(X11_image, x + i, line,
(unsigned)screen->palette[v].R << 16 | (unsigned)screen->palette[v].G << 8 | (unsigned)screen->palette[v].B);
}
#endif
}
XPutImage(X11_display, X11_window, X11_gc, X11_image,
x, y, x, y, width, height);
//XPutImage(X11_display, X11_window, X11_gc, X11_image,
// 0, 0, 0, 0, X11_image->width, X11_image->height);
//XSync(X11_display, False);
}
void Flush_update(void)
{
if (X11_display != NULL)
XFlush(X11_display);
}
void Update_status_line(short char_pos, short width)
{
Update_rect((18+char_pos*8)*Menu_factor_X*Pixel_width, Menu_status_Y*Pixel_height,
width*8*Menu_factor_X*Pixel_width, 8*Menu_factor_Y*Pixel_height);
}
void Clear_border(byte color)
{
(void)color;//TODO
}
volatile int Allow_colorcycling = 0;
/// Activates or desactivates file drag-dropping in program window.
void Allow_drag_and_drop(int flag)
{
(void)flag;
}
void Define_icon(void)
{
}

View File

@ -42,6 +42,31 @@ win32vk = {
'RALT': 'RMENU',
}
x11xk = {
'BACKSPACE': 'BackSpace',
'CAPSLOCK': 'Caps_Lock',
'PAGEUP': 'Page_Up',
'PAGEDOWN': 'Page_Down',
'BACKQUOTE': 'grave',
'KP_PLUS': 'KP_Add',
'KP_MINUS': 'KP_Subtract',
'KP_EQUALS': 'KP_Equal',
'KP_PERIOD': 'KP_Decimal',
'COMMA': 'comma',
'SPACE': 'space',
'EQUALS': 'equal',
'MINUS': 'minus',
'PERIOD': 'period',
'LEFTBRACKET': 'bracketleft',
'RIGHTBRACKET': 'bracketright',
'LCTRL': 'Control_L',
'RCTRL': 'Control_R',
'LALT': 'Alt_L',
'RALT': 'Alt_R',
'LSHIFT': 'Shift_L',
'RSHIFT': 'Shift_R',
}
def keycode_def(section, key, index, native_key=None):
if native_key is None:
native_key = key
@ -56,6 +81,13 @@ def keycode_def(section, key, index, native_key=None):
return '#define KEY_%-12s 0\n' % (key)
else:
return '#define KEY_%-12s VK_%s\n' % (key, native_key)
elif section == 'x11':
if native_key[0:3] == 'Kp_':
native_key = 'KP_' + native_key[3:]
if key == 'UNKNOWN':
return '#define KEY_%-12s 0\n' % (key)
else:
return '#define KEY_%-12s K2K(XK_%s)\n' % (key, native_key)
else:
return '#define KEY_%-12s %d\n' % (key, index)
@ -65,6 +97,11 @@ def add_keycodes_defs(section, lines):
for key in keys:
if section == 'win32' and key in win32vk:
lines.append(keycode_def(section, key, i, win32vk[key]))
elif section == 'x11':
if key in x11xk:
lines.append(keycode_def(section, key, i, x11xk[key]))
else:
lines.append(keycode_def(section, key, i, key.title()))
else:
lines.append(keycode_def(section, key, i))
i = i + 1
@ -80,11 +117,15 @@ def add_keycodes_defs(section, lines):
key = "KP%d" % (j)
if section == 'win32':
lines.append(keycode_def(section, key, i, "NUMPAD%d" % (j)))
elif section == 'x11':
lines.append(keycode_def(section, key, i, "KP_%d" % (j)))
else:
lines.append(keycode_def(section, key, i))
i = i + 1
if section == 'win32':
lines.append(keycode_def(section, 'SCROLLOCK', i, 'SCROLL'))
elif section == 'x11':
lines.append(keycode_def(section, 'SCROLLOCK', i, 'Scroll_Lock'))
else:
lines.append(keycode_def(section, 'SCROLLOCK', i))
i = i + 1