Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upUnicode input / output support in GUI #113
Comments
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
russellallen
Feb 20, 2017
Owner
Displaying unicode is very complicated :( The open source world seems to be relying mostly on the Harfbuzz/Pango which aren't simple (!) and which would need quite a bit of work to integrate into Self.
What is your native language? Which characters do you need apart from ASCII?
|
Displaying unicode is very complicated :( The open source world seems to be relying mostly on the Harfbuzz/Pango which aren't simple (!) and which would need quite a bit of work to integrate into Self. What is your native language? Which characters do you need apart from ASCII? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Feb 22, 2017
Contributor
What is your native language?
Czech language.
Which characters do you need apart from ASCII?
"á", "é", "ě", "í", "ó", "ú", "ů", "ý", "č", "ď", "ň", "ř", "š", "ť", "ž" and "Á", "É", "Ě", "Í", "Ó", "Ú", "Ů", "Ý", "Č", "Ď", "Ň", "Ř", "Š", "Ť", "Ž".
Czech language.
"á", "é", "ě", "í", "ó", "ú", "ů", "ý", "č", "ď", "ň", "ř", "š", "ť", "ž" and "Á", "É", "Ě", "Í", "Ó", "Ú", "Ů", "Ý", "Č", "Ď", "Ň", "Ř", "Š", "Ť", "Ž". |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
davidungar
Feb 22, 2017
Collaborator
|
Cool! Self was invented years before Unicode.
- David
… On Feb 22, 2017, at 5:48 AM, Bystroushaak ***@***.***> wrote:
What is your native language?
Czech language.
Which characters do you need apart from ASCII?
"á", "é", "ě", "í", "ó", "ú", "ů", "ý", "č", "ď", "ň", "ř", "š", "ť", "ž" and "Á", "É", "Ě", "Í", "Ó", "Ú", "Ů", "Ý", "Č", "Ď", "Ň", "Ř", "Š", "Ť", "Ž".
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 23, 2017
Contributor
I've offered to pay ~$500 to one C++ programmer I know to implement Xlib unicode input. He looked at Self and played with it for a while, but then decided, that he can't do it. He sent me this patch file.
I have no idea whether it is useful for something, but posting anyway for documentation purposes and maybe someone will use it.
diff --git a/vm/cmake/dependencies.cmake b/vm/cmake/dependencies.cmake
index 67e8535..7f17ac0 100644
--- a/vm/cmake/dependencies.cmake
+++ b/vm/cmake/dependencies.cmake
@@ -29,10 +29,12 @@ if(SELF_X11)
endif()
set(X11_INCLUDE_DIRS ${X11_INCLUDE_DIR})
endif()
+
+ pkg_check_modules(XFT REQUIRED xft)
- link_directories(${X11_LIBRARY_DIRS})
- include_directories(${X11_INCLUDE_DIRS})
- list(APPEND 3RD_PARTY_LIBS ${X11_LIBRARIES})
+ link_directories(${X11_LIBRARY_DIRS} ${XFT_LIBRARY_DIRS})
+ include_directories(${X11_INCLUDE_DIRS} ${XFT_INCLUDE_DIRS})
+ list(APPEND 3RD_PARTY_LIBS ${X11_LIBRARIES} ${XFT_LIBRARIES})
endif()
if(PKG_CONFIG_FOUND)
diff --git a/vm/src/any/os/xlibWindow.cpp b/vm/src/any/os/xlibWindow.cpp
index 2abf4d2..f23df24 100644
--- a/vm/src/any/os/xlibWindow.cpp
+++ b/vm/src/any/os/xlibWindow.cpp
@@ -16,8 +16,10 @@
XPlatformWindow::XPlatformWindow() : AbstractPlatformWindow() {
- _display = NULL;
- _font_info = NULL;
+ _display = NULL;
+ _gc = NULL;
+ _xft_drawable = NULL;
+ _xft_font = NULL;
}
@@ -27,45 +29,47 @@ bool XPlatformWindow::open( const char* display_name,
int x, int y, int w, int h,
int min_w, int max_w, int min_h, int max_h, // -1 for don't care
const char* window_name, const char* icon_name,
- const char* font_name, int /*font_size unimp X*/ ) {
+ const char* font_name, int font_size) {
// (adapted from Spy open routine, needs font info for sizing)
// XOpenDisplay fails silently if a signal is received during the call.
- // All signals except user interrupts are therefore blocked.
+ // All signals except user interrupts are therefore blocked.
SignalBlocker sb(SignalBlocker::allow_user_int);
-
+
if (!open_xdisplay(display_name)) { close(); return false; }
-
+
bool debugMe = false; // set to true when debugging X
- XSynchronize(_display, debugMe);
+ XSynchronize(_display, debugMe);
XSetErrorHandler(XErrorHandlers::handle_X_error);
_screen_num = DefaultScreen(_display);
+ _colormap = DefaultColormap(_display, _screen_num);
_display_width = DisplayWidth (_display, _screen_num);
_display_height = DisplayHeight(_display, _screen_num);
-
+
_window_x = x; _window_y = y; _width = w; _height = h;
// create the window; will be resized and repositioned when reparented
Window root = RootWindow(_display, _screen_num);
-
- _xwindow = XCreateSimpleWindow( _display, root,
- _window_x, _window_y,
- width(), height(), 0,
- BlackPixel(_display, _screen_num),
- WhitePixel(_display, _screen_num));
-
- if (!set_font_info(font_name)) { close(); return false; }
- if (!change_size_hints(min_w, max_w, min_h, max_h)) { close(); return false; }
-
+
+ _xwindow = XCreateSimpleWindow(_display, root,
+ _window_x, _window_y,
+ width(), height(), 0,
+ BlackPixel(_display, _screen_num),
+ WhitePixel(_display, _screen_num));
+
+ if (!setup_xft_drawable()) { close(); return false; }
+ if (!set_font_info(font_name, font_size)) { close(); return false; }
+ if (!change_size_hints(min_w, max_w, min_h, max_h)) { close(); return false; }
+
if (!set_name( window_name)) { close(); return false; }
if (!set_icon_name( icon_name)) { close(); return false; }
-
- setup_events();
+
+ setup_events();
XMapWindow(_display, _xwindow);
-
+
if (!setup_gcs()) { close(); return false; }
-
+
return true;
}
@@ -82,8 +86,8 @@ bool XPlatformWindow::open_xdisplay(const char *n) {
return true;
}
-
-bool XPlatformWindow::set_icon_name(const char* icon_name) {
+
+bool XPlatformWindow::set_icon_name(const char* icon_name) {
XTextProperty iconName;
if (XStringListToTextProperty((char**)&icon_name, 1, &iconName) == 0) {
warning("X structure allocation for icon name failed--window won't work.");
@@ -105,12 +109,12 @@ bool XPlatformWindow::set_name(const char* window_name) {
}
-void XPlatformWindow::setup_events() {
+void XPlatformWindow::setup_events() {
// to catch the clientMessage event when user deletes
_wmProtocolsAtom = XInternAtom(_display, "WM_PROTOCOLS", false);
_wmDeleteWindowAtom = XInternAtom(_display, "WM_DELETE_WINDOW", false);
XSetWMProtocols(_display, _xwindow, &_wmDeleteWindowAtom, 1);
-
+
// choose events to receive
long event_mask = ExposureMask | StructureNotifyMask;
XSelectInput(_display, _xwindow, event_mask);
@@ -120,7 +124,7 @@ void XPlatformWindow::setup_events() {
bool XPlatformWindow::tell_platform_size_hints() {
if ( _min_w == -1)
return true; // hack for don't care
-
+
// tell window manager that we'd like our own size and position
XSizeHints* size_hints;
if ((size_hints = XAllocSizeHints()) == NULL) {
@@ -138,10 +142,13 @@ bool XPlatformWindow::tell_platform_size_hints() {
}
-bool XPlatformWindow::set_font_info(const char* font_name) {
- // must set _font_info here so that font_height() is defined for BOTTOM
- _font_info = XLoadQueryFont(_display, font_name);
- return _font_info != NULL;
+bool XPlatformWindow::set_font_info(const char* font_name, int size) {
+ // must set _xft_font here so that font_height() is defined for BOTTOM
+ _xft_font = XftFontOpen(_display, _screen_num,
+ XFT_FAMILY, XftTypeString, font_name,
+ XFT_SIZE, XftTypeDouble, double(size),
+ NULL);
+ return _xft_font != NULL;
}
@@ -150,11 +157,10 @@ bool XPlatformWindow::setup_gcs() {
unsigned long valuemask = 0;
XGCValues values;
_gc = XCreateGC(_display, _xwindow, valuemask, &values);
-
- XSetFont(_display, _gc, _font_info->fid);
+
XSetForeground(_display, _gc, BlackPixel(_display, _screen_num));
XSetBackground(_display, _gc, WhitePixel(_display, _screen_num));
-
+
// 16x16 grey stipple pixmap (16x16 is preferred stipple size)
const int grey_width = 16;
const int grey_height = 16;
@@ -165,28 +171,35 @@ bool XPlatformWindow::setup_gcs() {
Pixmap stipple = XCreateBitmapFromData(_display, _xwindow, grey_bits,
grey_width, grey_height);
XSetStipple(_display, _gc, stipple);
-
+
_black= BlackPixel(_display, _screen_num);
_white= WhitePixel(_display, _screen_num);
_is_mono = DefaultDepth(_display, _screen_num) == 1;
if (_is_mono)
_red= _yellow= _gray= _black;
else {
- Colormap cmap= DefaultColormap(_display, _screen_num);
XColor col1, col2;
- _red= XAllocNamedColor(_display, cmap, "red", &col1, &col2)
+ _red= XAllocNamedColor(_display, _colormap, "red", &col1, &col2)
? col1.pixel : _black;
- _yellow= XAllocNamedColor(_display, cmap, "gold", &col1, &col2)
+ _yellow= XAllocNamedColor(_display, _colormap, "gold", &col1, &col2)
? col1.pixel : _black;
- _gray= XAllocNamedColor(_display, cmap, "gray", &col1, &col2)
+ _gray= XAllocNamedColor(_display, _colormap, "gray", &col1, &col2)
? col1.pixel : _black;
}
return true;
}
-void XPlatformWindow::close() {
- if (_font_info != NULL) { XFreeFont(_display, _font_info); _font_info = NULL; }
+void XPlatformWindow::close() {
+ if (_xft_font) {
+ XftFontClose(_display, _xft_font);
+ _xft_font = NULL;
+ }
+ if (_xft_drawable) {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ XftDrawDestroy(_xft_drawable);
+ _xft_drawable = NULL;
+ }
if (_gc != NULL) { XFreeGC( _display, _gc); _gc = NULL; }
if (_display != NULL) { XCloseDisplay(_display); _display = NULL; }
}
@@ -213,17 +226,17 @@ int XPlatformWindow::height() { return _height; }
int XPlatformWindow::screen_width() { return _display_width; }
int XPlatformWindow::screen_height() { return _display_height; }
int XPlatformWindow::menubar_height() { return 0; } // none in X
-
-int XPlatformWindow::font_width() { return _font_info->max_bounds.width; }
-int XPlatformWindow::font_height() { return _font_info->max_bounds.ascent + _font_info->max_bounds.descent; }
-const char* XPlatformWindow::default_fixed_font_name() { return "fixed"; }
+int XPlatformWindow::font_width() { return _xft_font->max_advance_width; }
+int XPlatformWindow::font_height() { return _xft_font->height; }
+
+const char* XPlatformWindow::default_fixed_font_name() { return "monospace"; }
int XPlatformWindow::default_fixed_font_size() { return 10; }
// Handy operations;
-bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
+bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
// left, top in global coordinates
// don't need to adjust by insets for X
XMoveResizeWindow(_display, _xwindow, left, top, w, h);
@@ -233,7 +246,7 @@ bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
_height = h;
return true;
}
-void XPlatformWindow::adjust_after_resize() {
+void XPlatformWindow::adjust_after_resize() {
if (TheSpy != NULL)
TheSpy->adjust_after_resize(); // in case this is the spy
}
@@ -255,7 +268,12 @@ bool XPlatformWindow:: pre_draw( bool incremental) {
void XPlatformWindow::post_draw( bool ) { /* XFlush(_display); should be needed but was not there before */ }
void XPlatformWindow::draw_text(const char* text, int x, int y) {
- XDrawImageString(_display, _xwindow, _gc, x, y, text, strlen(text));
+ assert(_xft_drawable);
+ assert(_xft_font);
+
+ XftDrawStringUtf8(_xft_drawable, &_foreground_xft_color,
+ _xft_font, x, y, (FcChar8*)text,
+ strlen(text));
}
void XPlatformWindow::draw_line(int x1, int y1, int x2, int y2) {
@@ -266,7 +284,7 @@ void XPlatformWindow::draw_rectangle_black(int x, int y, int w, int h) {
if (w > 0 && h > 0)
XDrawRectangle(_display, _xwindow, _gc, x, y, w, h);
}
-
+
void XPlatformWindow::clear_rectangle(int x, int y, int w, int h) {
if (w > 0 && h > 0)
@@ -275,23 +293,82 @@ void XPlatformWindow::clear_rectangle(int x, int y, int w, int h) {
// X drawing functions
-// the X calls do the wrong thing if w or h is 0, so suppress these calls
+// the X calls do the wrong thing if w or h is 0, so suppress these calls
void XPlatformWindow::fill_rectangle(int x, int y, int w, int h) {
if (w > 0 && h > 0)
XFillRectangle(_display, _xwindow, _gc, x, y, w, h);
}
-void XPlatformWindow::set_color(int c) { XSetForeground (_display, _gc, c); }
+void XPlatformWindow::set_color(int c) {
+ XSetForeground(_display, _gc, c);
+ set_xft_color_from_pixel(c);
+}
+
void XPlatformWindow::set_thickness(int t) { XSetLineAttributes(_display, _gc, t, LineSolid, CapButt, JoinMiter); }
void XPlatformWindow::set_xor() { XSetFunction (_display, _gc, GXxor); }
void XPlatformWindow::set_copy() { XSetFunction (_display, _gc, GXcopy); }
+bool XPlatformWindow::setup_xft_drawable()
+{
+ _foreground_render_color.red = 0;
+ _foreground_render_color.green = 0;
+ _foreground_render_color.blue = 0;
+ _foreground_render_color.alpha = 65535u;
+
+ if (!XftColorAllocValue(_display,
+ DefaultVisual(_display, _screen_num),
+ _colormap,
+ &_foreground_render_color,
+ &_foreground_xft_color))
+ {
+ return false;
+ }
+
+ _xft_drawable = XftDrawCreate(_display,
+ _xwindow,
+ DefaultVisual(_display, _screen_num),
+ _colormap);
+ if (!_xft_drawable)
+ {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ return false;
+ }
-bool XPlatformWindow::get_graphics_semaphore() {
+ return true;
+}
+
+void XPlatformWindow::set_xft_color_from_pixel(unsigned long pixel)
+{
+ XColor xcolor = {0};
+ xcolor.pixel = pixel;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ XQueryColor(_display, _colormap, &xcolor);
+
+ XRenderColor renderColor;
+ renderColor.red = xcolor.red;
+ renderColor.green = xcolor.green;
+ renderColor.blue = xcolor.blue;
+ renderColor.alpha = 65535u;
+
+ XftColor xftColor;
+
+ if (XftColorAllocValue(_display,
+ DefaultVisual(_display, _screen_num),
+ _colormap,
+ &renderColor,
+ &xftColor))
+ {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ _foreground_render_color = renderColor;
+ _foreground_xft_color = xftColor;
+ }
+}
+
+bool XPlatformWindow::get_graphics_semaphore() {
// if you draw while X may be drawing something else, check this
// and don't draw if it is true
- extern bool xlib_semaphore;
+ extern bool xlib_semaphore;
return xlib_semaphore;
}
@@ -306,22 +383,22 @@ bool XPlatformWindow::handle_polled_events() {
while ( XPending(_display) > 0 ) {
XNextEvent(_display, &event);
switch (event.type) {
-
+
case Expose:
if (event.xexpose.count != 0) break;
full_redraw(); // force redraw
break;
-
+
case ConfigureNotify:
_width = event.xconfigure.width;
_height = event.xconfigure.height;
adjust_after_resize();
break;
-
- case ReparentNotify:
+
+ case ReparentNotify:
handle_reparent_event(event);
break;
-
+
case ClientMessage:
if ((event.xclient.message_type = _wmProtocolsAtom)
&& (event.xclient.data.l[0] = _wmDeleteWindowAtom)) {
@@ -330,7 +407,7 @@ bool XPlatformWindow::handle_polled_events() {
return false;
}
break;
-
+
default:
break;
}
@@ -344,13 +421,13 @@ void XPlatformWindow::handle_reparent_event(XEvent& event) {
int x, y;
unsigned w, h, border_width, depth;
if (XGetGeometry(_display, event.xreparent.parent, &root, &x, &y,
- &w, &h, &border_width, &depth) == 0)
+ &w, &h, &border_width, &depth) == 0)
return;
int wdelta = w - width();
// sanity check: sometimes X gives weird width
if (wdelta < 0) {
if (XGetGeometry(_display, event.xreparent.parent, &root, &x, &y,
- &w, &h, &border_width, &depth) == 0)
+ &w, &h, &border_width, &depth) == 0)
return;
wdelta = w - width();
if (wdelta < 0) {
diff --git a/vm/src/any/os/xlibWindow.hh b/vm/src/any/os/xlibWindow.hh
index 396bf5a..a6c43d0 100644
--- a/vm/src/any/os/xlibWindow.hh
+++ b/vm/src/any/os/xlibWindow.hh
@@ -20,11 +20,15 @@ class XPlatformWindow: public AbstractPlatformWindow {
int _screen_num;
int _display_width, _display_height;
Window _xwindow;
+ XftDraw* _xft_drawable;
+ Colormap _colormap;
int _window_x, _window_y;
- int _width, _height;
- XFontStruct* _font_info;
+ int _width, _height;
+ XftFont* _xft_font;
Atom _wmProtocolsAtom, _wmDeleteWindowAtom;
GC _gc;
+ XRenderColor _foreground_render_color;
+ XftColor _foreground_xft_color;
bool _is_mono;
public:
@@ -90,11 +94,14 @@ class XPlatformWindow: public AbstractPlatformWindow {
// Open helpers
bool open_xdisplay(const char*);
void setup_events();
+ bool setup_xft_drawable();
bool set_name(const char*);
bool set_icon_name(const char*);
- bool set_font_info(const char*);
+ bool set_font_info(const char*, int size);
bool setup_gcs();
+ void set_xft_color_from_pixel(unsigned long pixel);
+
// Drawing helpers
bool get_graphics_semaphore(); // X is not reentrant
diff --git a/vm/src/unix/prims/x_includes.hh b/vm/src/unix/prims/x_includes.hh
index 9349ee8..06db282 100644
--- a/vm/src/unix/prims/x_includes.hh
+++ b/vm/src/unix/prims/x_includes.hh
@@ -12,6 +12,7 @@
# define Cursor SelfX11Cursor // prevent clash with Carbon
# include <X11/Xlib.h>
# include <X11/Xutil.h>
+# include <X11/Xft/Xft.h>
# undef Cursor
# if TARGET_OS_VERSION == MACOSX_VERSION
# undef Status|
I've offered to pay ~$500 to one C++ programmer I know to implement Xlib unicode input. He looked at Self and played with it for a while, but then decided, that he can't do it. He sent me this patch file. I have no idea whether it is useful for something, but posting anyway for documentation purposes and maybe someone will use it. diff --git a/vm/cmake/dependencies.cmake b/vm/cmake/dependencies.cmake
index 67e8535..7f17ac0 100644
--- a/vm/cmake/dependencies.cmake
+++ b/vm/cmake/dependencies.cmake
@@ -29,10 +29,12 @@ if(SELF_X11)
endif()
set(X11_INCLUDE_DIRS ${X11_INCLUDE_DIR})
endif()
+
+ pkg_check_modules(XFT REQUIRED xft)
- link_directories(${X11_LIBRARY_DIRS})
- include_directories(${X11_INCLUDE_DIRS})
- list(APPEND 3RD_PARTY_LIBS ${X11_LIBRARIES})
+ link_directories(${X11_LIBRARY_DIRS} ${XFT_LIBRARY_DIRS})
+ include_directories(${X11_INCLUDE_DIRS} ${XFT_INCLUDE_DIRS})
+ list(APPEND 3RD_PARTY_LIBS ${X11_LIBRARIES} ${XFT_LIBRARIES})
endif()
if(PKG_CONFIG_FOUND)
diff --git a/vm/src/any/os/xlibWindow.cpp b/vm/src/any/os/xlibWindow.cpp
index 2abf4d2..f23df24 100644
--- a/vm/src/any/os/xlibWindow.cpp
+++ b/vm/src/any/os/xlibWindow.cpp
@@ -16,8 +16,10 @@
XPlatformWindow::XPlatformWindow() : AbstractPlatformWindow() {
- _display = NULL;
- _font_info = NULL;
+ _display = NULL;
+ _gc = NULL;
+ _xft_drawable = NULL;
+ _xft_font = NULL;
}
@@ -27,45 +29,47 @@ bool XPlatformWindow::open( const char* display_name,
int x, int y, int w, int h,
int min_w, int max_w, int min_h, int max_h, // -1 for don't care
const char* window_name, const char* icon_name,
- const char* font_name, int /*font_size unimp X*/ ) {
+ const char* font_name, int font_size) {
// (adapted from Spy open routine, needs font info for sizing)
// XOpenDisplay fails silently if a signal is received during the call.
- // All signals except user interrupts are therefore blocked.
+ // All signals except user interrupts are therefore blocked.
SignalBlocker sb(SignalBlocker::allow_user_int);
-
+
if (!open_xdisplay(display_name)) { close(); return false; }
-
+
bool debugMe = false; // set to true when debugging X
- XSynchronize(_display, debugMe);
+ XSynchronize(_display, debugMe);
XSetErrorHandler(XErrorHandlers::handle_X_error);
_screen_num = DefaultScreen(_display);
+ _colormap = DefaultColormap(_display, _screen_num);
_display_width = DisplayWidth (_display, _screen_num);
_display_height = DisplayHeight(_display, _screen_num);
-
+
_window_x = x; _window_y = y; _width = w; _height = h;
// create the window; will be resized and repositioned when reparented
Window root = RootWindow(_display, _screen_num);
-
- _xwindow = XCreateSimpleWindow( _display, root,
- _window_x, _window_y,
- width(), height(), 0,
- BlackPixel(_display, _screen_num),
- WhitePixel(_display, _screen_num));
-
- if (!set_font_info(font_name)) { close(); return false; }
- if (!change_size_hints(min_w, max_w, min_h, max_h)) { close(); return false; }
-
+
+ _xwindow = XCreateSimpleWindow(_display, root,
+ _window_x, _window_y,
+ width(), height(), 0,
+ BlackPixel(_display, _screen_num),
+ WhitePixel(_display, _screen_num));
+
+ if (!setup_xft_drawable()) { close(); return false; }
+ if (!set_font_info(font_name, font_size)) { close(); return false; }
+ if (!change_size_hints(min_w, max_w, min_h, max_h)) { close(); return false; }
+
if (!set_name( window_name)) { close(); return false; }
if (!set_icon_name( icon_name)) { close(); return false; }
-
- setup_events();
+
+ setup_events();
XMapWindow(_display, _xwindow);
-
+
if (!setup_gcs()) { close(); return false; }
-
+
return true;
}
@@ -82,8 +86,8 @@ bool XPlatformWindow::open_xdisplay(const char *n) {
return true;
}
-
-bool XPlatformWindow::set_icon_name(const char* icon_name) {
+
+bool XPlatformWindow::set_icon_name(const char* icon_name) {
XTextProperty iconName;
if (XStringListToTextProperty((char**)&icon_name, 1, &iconName) == 0) {
warning("X structure allocation for icon name failed--window won't work.");
@@ -105,12 +109,12 @@ bool XPlatformWindow::set_name(const char* window_name) {
}
-void XPlatformWindow::setup_events() {
+void XPlatformWindow::setup_events() {
// to catch the clientMessage event when user deletes
_wmProtocolsAtom = XInternAtom(_display, "WM_PROTOCOLS", false);
_wmDeleteWindowAtom = XInternAtom(_display, "WM_DELETE_WINDOW", false);
XSetWMProtocols(_display, _xwindow, &_wmDeleteWindowAtom, 1);
-
+
// choose events to receive
long event_mask = ExposureMask | StructureNotifyMask;
XSelectInput(_display, _xwindow, event_mask);
@@ -120,7 +124,7 @@ void XPlatformWindow::setup_events() {
bool XPlatformWindow::tell_platform_size_hints() {
if ( _min_w == -1)
return true; // hack for don't care
-
+
// tell window manager that we'd like our own size and position
XSizeHints* size_hints;
if ((size_hints = XAllocSizeHints()) == NULL) {
@@ -138,10 +142,13 @@ bool XPlatformWindow::tell_platform_size_hints() {
}
-bool XPlatformWindow::set_font_info(const char* font_name) {
- // must set _font_info here so that font_height() is defined for BOTTOM
- _font_info = XLoadQueryFont(_display, font_name);
- return _font_info != NULL;
+bool XPlatformWindow::set_font_info(const char* font_name, int size) {
+ // must set _xft_font here so that font_height() is defined for BOTTOM
+ _xft_font = XftFontOpen(_display, _screen_num,
+ XFT_FAMILY, XftTypeString, font_name,
+ XFT_SIZE, XftTypeDouble, double(size),
+ NULL);
+ return _xft_font != NULL;
}
@@ -150,11 +157,10 @@ bool XPlatformWindow::setup_gcs() {
unsigned long valuemask = 0;
XGCValues values;
_gc = XCreateGC(_display, _xwindow, valuemask, &values);
-
- XSetFont(_display, _gc, _font_info->fid);
+
XSetForeground(_display, _gc, BlackPixel(_display, _screen_num));
XSetBackground(_display, _gc, WhitePixel(_display, _screen_num));
-
+
// 16x16 grey stipple pixmap (16x16 is preferred stipple size)
const int grey_width = 16;
const int grey_height = 16;
@@ -165,28 +171,35 @@ bool XPlatformWindow::setup_gcs() {
Pixmap stipple = XCreateBitmapFromData(_display, _xwindow, grey_bits,
grey_width, grey_height);
XSetStipple(_display, _gc, stipple);
-
+
_black= BlackPixel(_display, _screen_num);
_white= WhitePixel(_display, _screen_num);
_is_mono = DefaultDepth(_display, _screen_num) == 1;
if (_is_mono)
_red= _yellow= _gray= _black;
else {
- Colormap cmap= DefaultColormap(_display, _screen_num);
XColor col1, col2;
- _red= XAllocNamedColor(_display, cmap, "red", &col1, &col2)
+ _red= XAllocNamedColor(_display, _colormap, "red", &col1, &col2)
? col1.pixel : _black;
- _yellow= XAllocNamedColor(_display, cmap, "gold", &col1, &col2)
+ _yellow= XAllocNamedColor(_display, _colormap, "gold", &col1, &col2)
? col1.pixel : _black;
- _gray= XAllocNamedColor(_display, cmap, "gray", &col1, &col2)
+ _gray= XAllocNamedColor(_display, _colormap, "gray", &col1, &col2)
? col1.pixel : _black;
}
return true;
}
-void XPlatformWindow::close() {
- if (_font_info != NULL) { XFreeFont(_display, _font_info); _font_info = NULL; }
+void XPlatformWindow::close() {
+ if (_xft_font) {
+ XftFontClose(_display, _xft_font);
+ _xft_font = NULL;
+ }
+ if (_xft_drawable) {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ XftDrawDestroy(_xft_drawable);
+ _xft_drawable = NULL;
+ }
if (_gc != NULL) { XFreeGC( _display, _gc); _gc = NULL; }
if (_display != NULL) { XCloseDisplay(_display); _display = NULL; }
}
@@ -213,17 +226,17 @@ int XPlatformWindow::height() { return _height; }
int XPlatformWindow::screen_width() { return _display_width; }
int XPlatformWindow::screen_height() { return _display_height; }
int XPlatformWindow::menubar_height() { return 0; } // none in X
-
-int XPlatformWindow::font_width() { return _font_info->max_bounds.width; }
-int XPlatformWindow::font_height() { return _font_info->max_bounds.ascent + _font_info->max_bounds.descent; }
-const char* XPlatformWindow::default_fixed_font_name() { return "fixed"; }
+int XPlatformWindow::font_width() { return _xft_font->max_advance_width; }
+int XPlatformWindow::font_height() { return _xft_font->height; }
+
+const char* XPlatformWindow::default_fixed_font_name() { return "monospace"; }
int XPlatformWindow::default_fixed_font_size() { return 10; }
// Handy operations;
-bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
+bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
// left, top in global coordinates
// don't need to adjust by insets for X
XMoveResizeWindow(_display, _xwindow, left, top, w, h);
@@ -233,7 +246,7 @@ bool XPlatformWindow::change_extent(int left, int top, int w, int h) {
_height = h;
return true;
}
-void XPlatformWindow::adjust_after_resize() {
+void XPlatformWindow::adjust_after_resize() {
if (TheSpy != NULL)
TheSpy->adjust_after_resize(); // in case this is the spy
}
@@ -255,7 +268,12 @@ bool XPlatformWindow:: pre_draw( bool incremental) {
void XPlatformWindow::post_draw( bool ) { /* XFlush(_display); should be needed but was not there before */ }
void XPlatformWindow::draw_text(const char* text, int x, int y) {
- XDrawImageString(_display, _xwindow, _gc, x, y, text, strlen(text));
+ assert(_xft_drawable);
+ assert(_xft_font);
+
+ XftDrawStringUtf8(_xft_drawable, &_foreground_xft_color,
+ _xft_font, x, y, (FcChar8*)text,
+ strlen(text));
}
void XPlatformWindow::draw_line(int x1, int y1, int x2, int y2) {
@@ -266,7 +284,7 @@ void XPlatformWindow::draw_rectangle_black(int x, int y, int w, int h) {
if (w > 0 && h > 0)
XDrawRectangle(_display, _xwindow, _gc, x, y, w, h);
}
-
+
void XPlatformWindow::clear_rectangle(int x, int y, int w, int h) {
if (w > 0 && h > 0)
@@ -275,23 +293,82 @@ void XPlatformWindow::clear_rectangle(int x, int y, int w, int h) {
// X drawing functions
-// the X calls do the wrong thing if w or h is 0, so suppress these calls
+// the X calls do the wrong thing if w or h is 0, so suppress these calls
void XPlatformWindow::fill_rectangle(int x, int y, int w, int h) {
if (w > 0 && h > 0)
XFillRectangle(_display, _xwindow, _gc, x, y, w, h);
}
-void XPlatformWindow::set_color(int c) { XSetForeground (_display, _gc, c); }
+void XPlatformWindow::set_color(int c) {
+ XSetForeground(_display, _gc, c);
+ set_xft_color_from_pixel(c);
+}
+
void XPlatformWindow::set_thickness(int t) { XSetLineAttributes(_display, _gc, t, LineSolid, CapButt, JoinMiter); }
void XPlatformWindow::set_xor() { XSetFunction (_display, _gc, GXxor); }
void XPlatformWindow::set_copy() { XSetFunction (_display, _gc, GXcopy); }
+bool XPlatformWindow::setup_xft_drawable()
+{
+ _foreground_render_color.red = 0;
+ _foreground_render_color.green = 0;
+ _foreground_render_color.blue = 0;
+ _foreground_render_color.alpha = 65535u;
+
+ if (!XftColorAllocValue(_display,
+ DefaultVisual(_display, _screen_num),
+ _colormap,
+ &_foreground_render_color,
+ &_foreground_xft_color))
+ {
+ return false;
+ }
+
+ _xft_drawable = XftDrawCreate(_display,
+ _xwindow,
+ DefaultVisual(_display, _screen_num),
+ _colormap);
+ if (!_xft_drawable)
+ {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ return false;
+ }
-bool XPlatformWindow::get_graphics_semaphore() {
+ return true;
+}
+
+void XPlatformWindow::set_xft_color_from_pixel(unsigned long pixel)
+{
+ XColor xcolor = {0};
+ xcolor.pixel = pixel;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ XQueryColor(_display, _colormap, &xcolor);
+
+ XRenderColor renderColor;
+ renderColor.red = xcolor.red;
+ renderColor.green = xcolor.green;
+ renderColor.blue = xcolor.blue;
+ renderColor.alpha = 65535u;
+
+ XftColor xftColor;
+
+ if (XftColorAllocValue(_display,
+ DefaultVisual(_display, _screen_num),
+ _colormap,
+ &renderColor,
+ &xftColor))
+ {
+ XftColorFree(_display, DefaultVisual(_display, _screen_num), _colormap, &_foreground_xft_color);
+ _foreground_render_color = renderColor;
+ _foreground_xft_color = xftColor;
+ }
+}
+
+bool XPlatformWindow::get_graphics_semaphore() {
// if you draw while X may be drawing something else, check this
// and don't draw if it is true
- extern bool xlib_semaphore;
+ extern bool xlib_semaphore;
return xlib_semaphore;
}
@@ -306,22 +383,22 @@ bool XPlatformWindow::handle_polled_events() {
while ( XPending(_display) > 0 ) {
XNextEvent(_display, &event);
switch (event.type) {
-
+
case Expose:
if (event.xexpose.count != 0) break;
full_redraw(); // force redraw
break;
-
+
case ConfigureNotify:
_width = event.xconfigure.width;
_height = event.xconfigure.height;
adjust_after_resize();
break;
-
- case ReparentNotify:
+
+ case ReparentNotify:
handle_reparent_event(event);
break;
-
+
case ClientMessage:
if ((event.xclient.message_type = _wmProtocolsAtom)
&& (event.xclient.data.l[0] = _wmDeleteWindowAtom)) {
@@ -330,7 +407,7 @@ bool XPlatformWindow::handle_polled_events() {
return false;
}
break;
-
+
default:
break;
}
@@ -344,13 +421,13 @@ void XPlatformWindow::handle_reparent_event(XEvent& event) {
int x, y;
unsigned w, h, border_width, depth;
if (XGetGeometry(_display, event.xreparent.parent, &root, &x, &y,
- &w, &h, &border_width, &depth) == 0)
+ &w, &h, &border_width, &depth) == 0)
return;
int wdelta = w - width();
// sanity check: sometimes X gives weird width
if (wdelta < 0) {
if (XGetGeometry(_display, event.xreparent.parent, &root, &x, &y,
- &w, &h, &border_width, &depth) == 0)
+ &w, &h, &border_width, &depth) == 0)
return;
wdelta = w - width();
if (wdelta < 0) {
diff --git a/vm/src/any/os/xlibWindow.hh b/vm/src/any/os/xlibWindow.hh
index 396bf5a..a6c43d0 100644
--- a/vm/src/any/os/xlibWindow.hh
+++ b/vm/src/any/os/xlibWindow.hh
@@ -20,11 +20,15 @@ class XPlatformWindow: public AbstractPlatformWindow {
int _screen_num;
int _display_width, _display_height;
Window _xwindow;
+ XftDraw* _xft_drawable;
+ Colormap _colormap;
int _window_x, _window_y;
- int _width, _height;
- XFontStruct* _font_info;
+ int _width, _height;
+ XftFont* _xft_font;
Atom _wmProtocolsAtom, _wmDeleteWindowAtom;
GC _gc;
+ XRenderColor _foreground_render_color;
+ XftColor _foreground_xft_color;
bool _is_mono;
public:
@@ -90,11 +94,14 @@ class XPlatformWindow: public AbstractPlatformWindow {
// Open helpers
bool open_xdisplay(const char*);
void setup_events();
+ bool setup_xft_drawable();
bool set_name(const char*);
bool set_icon_name(const char*);
- bool set_font_info(const char*);
+ bool set_font_info(const char*, int size);
bool setup_gcs();
+ void set_xft_color_from_pixel(unsigned long pixel);
+
// Drawing helpers
bool get_graphics_semaphore(); // X is not reentrant
diff --git a/vm/src/unix/prims/x_includes.hh b/vm/src/unix/prims/x_includes.hh
index 9349ee8..06db282 100644
--- a/vm/src/unix/prims/x_includes.hh
+++ b/vm/src/unix/prims/x_includes.hh
@@ -12,6 +12,7 @@
# define Cursor SelfX11Cursor // prevent clash with Carbon
# include <X11/Xlib.h>
# include <X11/Xutil.h>
+# include <X11/Xft/Xft.h>
# undef Cursor
# if TARGET_OS_VERSION == MACOSX_VERSION
# undef Status |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
doublec
Apr 23, 2017
Collaborator
Back when I looked at Linux fonts and Xft I think I tried XPlatformWindow too, but it wasn't where the font code was being done. It's done in Self. I wrote a post on how to do Xft fonts from Self with the code in this branch. It adds the primitives to enable displaying fonts but doesn't hook it into the existing font code. You'd probably need to follow how the Mac OS Self code does this as it also uses a different font mechanism.
|
Back when I looked at Linux fonts and Xft I think I tried XPlatformWindow too, but it wasn't where the font code was being done. It's done in Self. I wrote a post on how to do Xft fonts from Self with the code in this branch. It adds the primitives to enable displaying fonts but doesn't hook it into the existing font code. You'd probably need to follow how the Mac OS Self code does this as it also uses a different font mechanism. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 24, 2017
Contributor
I will have to look how is input handled. I suspect, that there may be just some condition that prevents input of any character that self doesn't understand. In the terminal, everything works as expected:
"Self 1" 'č'
'\xc4\x8d'
|
I will have to look how is input handled. I suspect, that there may be just some condition that prevents input of any character that self doesn't understand. In the terminal, everything works as expected:
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
russellallen
Apr 24, 2017
Owner
"Self 5" 'ç' printLine ç '\xc3\xa7'
printing to console works too.
To do this right shouldn't we transition to a utf8 string type - detach traits string from traits byteVector and make it standalone to handle multibyte characters etc?
|
printing to console works too. To do this right shouldn't we transition to a utf8 string type - detach |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 24, 2017
Contributor
To do this right shouldn't we transition to a utf8 string type - detach traits string from traits byteVector and make it standalone to handle multibyte characters etc?
That would be ideal, but I think that input and output has higher priority.
UTF API support is nice thing to have, but you can work around it, if you don't (for example - search for substring, instead of single character). Missing UTF input means, that you literally can't type into the application you are trying to build, which makes it unusable.
I was again looking into the X wrappers yesterday, but the more I see, the less I understand how it actually works. I was talking about it with few C++/Unix programmers, but they all run away when they've seen primitive maker and how the bindings are connected
That would be ideal, but I think that input and output has higher priority. UTF API support is nice thing to have, but you can work around it, if you don't (for example - search for substring, instead of single character). Missing UTF input means, that you literally can't type into the application you are trying to build, which makes it unusable. I was again looking into the X wrappers yesterday, but the more I see, the less I understand how it actually works. I was talking about it with few C++/Unix programmers, but they all run away when they've seen primitive maker and how the bindings are connected |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 24, 2017
Contributor
I've managed to trace the input into the traits abstractUI2Event editorKeyCapComboHandler, where is code for handling the input like handlePressWithNoModifiers: combo IfCannot: b, which is limited only to printable characters by this line:
combo nonmodifierKeyCap isPrintable ifTrue: [^combo nonmodifierKeyCap printString do: [|:c| insert_char: c]].
isPrintable is message from string and it just checks whether the character is > 32 && < 128, which limits the input for characters with higher code. When I allowed higher codes (by changing isPrintable implementation), it is now possible to enter ýáíéú (and they also display correctly!), but not ěščřžů or any combining keys (' + a = á, ˇ + d = ď and so on). I am not yet sure why. What I find really strange that using autocutsel, I can copy the written characters out of Self, but when I try to paste them back, garbage occurs.
I am not sure, how is handlePressWithNoModifiers: combo IfCannot: b connected with general Self input and whether this code is just for the editor, or all input. Probably for all input from what I can read from sendMessageToHandleKeyboardEventTo:.
I will need to play with the input system a little bit more to understand how it would be possible to allow any input.
Note to my future self: Is it possible to define combo to include unicode character?
|
I've managed to trace the input into the
I am not sure, how is I will need to play with the input system a little bit more to understand how it would be possible to allow any input. Note to my future self: Is it possible to define |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 25, 2017
Contributor
I've played with Self again today and managed to trace the input handling into the:
traits abstractUI2Event editorKeyCapComboHandlerwhere ishandlePressWithNoModifiers: combo IfCannot: b
This may be updated to accept any character input by changing:
combo nonmodifierKeyCap isPrintable ifTrue: [^combo nonmodifierKeyCap printString do: [|:c| insert_char: c]].
to
combo nonmodifierKeyCap printString size <= 6 ifTrue: [^combo nonmodifierKeyCap printString do: [|:c| insert_char: c]].
That is the easier part, which will allow input such as éíáý (ISO 8859-1 btw), as I discovered yesterday.
The harder part is keyboard event handling in traits ui2XEvent, specifically keySymFrom: xEvt, which is defined as:
| k |
k: xEvt lookupKeySym.
k = xEvt xk_Left ifTrue: [ ^ keyCaps arrows left ].
k = xEvt xk_Up ifTrue: [ ^ keyCaps arrows up ].
k = xEvt xk_Right ifTrue: [ ^ keyCaps arrows right ].
k = xEvt xk_Down ifTrue: [ ^ keyCaps arrows down ].
k = xEvt xk_KP_Left ifTrue: [ ^ keyCaps arrows left ].
k = xEvt xk_KP_Up ifTrue: [ ^ keyCaps arrows up ].
k = xEvt xk_KP_Right ifTrue: [ ^ keyCaps arrows right ].
k = xEvt xk_KP_Down ifTrue: [ ^ keyCaps arrows down ].
k = xEvt xk_Shift_L ifTrue: [ ^ keyCaps oddballs shift ].
k = xEvt xk_Shift_R ifTrue: [ ^ keyCaps oddballs shift ].
k = xEvt xk_Control_L ifTrue: [ ^ keyCaps oddballs control ].
k = xEvt xk_Control_R ifTrue: [ ^ keyCaps oddballs control ].
k = xEvt xk_Alt_L ifTrue: [ ^ keyCaps oddballs alt ].
k = xEvt xk_Alt_R ifTrue: [ ^ keyCaps oddballs alt ].
k = xEvt xk_Super_L ifTrue: [ ^ keyCaps oddballs command ].
k = xEvt xk_Super_R ifTrue: [ ^ keyCaps oddballs command ].
keyCaps unknown
This is translator from unrecognized key codes to appropriate characters / strings.
By inserting
k = 488 ifTrue: [^ keyCaps printableCharacter copy character: '\xa9'].
before keyCaps unknown, I was able to map č key (keysym 0x1e8, =488) to '\xa9' ISO 8859-1 character (© mark). It is also possible to enter unicode strings such as '\xc4\x8d', but they will of course display itself as garbage (Ä⬚), because they are interpreted as ISO 8859-1.
Important point is, that translation from keysym to strings may be done here. I've tried xEvt lookupString, which may be used to resolve some of the other keys, but it returns empty strings for keys like č.
Now, the question is whether there is any possibility for mapping the keysyms (or keycode (=13), both are in xEvt object) to proper unicode representations automatically by calling some X function and half of the work is done.
|
I've played with Self again today and managed to trace the input handling into the:
This may be updated to accept any character input by changing:
to
That is the easier part, which will allow input such as éíáý (ISO 8859-1 btw), as I discovered yesterday. The harder part is keyboard event handling in
This is translator from unrecognized key codes to appropriate characters / strings. By inserting
before Important point is, that translation from keysym to strings may be done here. I've tried Now, the question is whether there is any possibility for mapping the keysyms (or keycode (=13), both are in xEvt object) to proper unicode representations automatically by calling some X function and half of the work is done. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 29, 2017
Contributor
I was thinking about implementing translation table for keysyms in Self, but decided I will try to do it in C++ Xlib code, because I don't want to replicate functionality, which is already there.
I am able to get UTF-8 input for almost* all keys, by modification of https://github.com/russellallen/self/blob/master/objects/glue/xlib_glue.cpp#L448:
from:
int XLookupString_wrap(XKeyEvent* event, char* string, int len,
objVectorOop keySym) {
KeySym ks;
int n = XLookupString(event, string, len, &ks, NULL);
if (keySym->length() >= 1) keySym->obj_at_put(0, as_smiOop(ks), false);
return n;
}to:
XIC getXICContext(XKeyEvent* event){
XIM im = XOpenIM(event->display, NULL, NULL, NULL);
XIC ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, event->window, NULL);
XSetICFocus(ic);
return ic;
}
int XLookupString_wrap(XKeyEvent* event, char* string, int len,
objVectorOop keySym) {
KeySym ks;
int n = Xutf8LookupString(getXICContext(event), event, string, len, &ks, NULL);
if (keySym->length() >= 1)
keySym->obj_at_put(0, as_smiOop(ks), false);
return n;
}It is basically just using Xutf8LookupString instead of XLookupString. It works nicely for keys like á.
*Except combining / dead keys (´ + a = á). They should somehow work with XFilterEvent, but I wasn't able to make it work. I've tried to modify XNextEvent_wrap from:
oop XNextEvent_wrap(Display *display, bool peek,
objVectorOop eventProtos, void *FH) {
XEvent *evt = new XEvent();
if (peek)
XPeekEvent(display, evt);
else
XNextEvent(display, evt);
int type = evt->type;
if (type < 0 || type >= eventProtos->length()) {
char err[50];
sprintf(err, "unknown X event, type = %d", type);
failure(FH, err);
delete evt;
return NULL;
}
oop proto = eventProtos->obj_at(type);
if (!proto->is_proxy()) {
prim_failure(FH, BADTYPEERROR);
delete evt;
return NULL;
}
proxyOop res = proxyOop(proto)->clone();
res->set_pointer(evt);
res->set_type_seal(XEvent_seal);
return res;
}to:
oop XNextEvent_wrap(Display *display, bool peek,
objVectorOop eventProtos, void *FH) {
XEvent *evt = new XEvent();
if (peek)
XPeekEvent(display, evt);
else
XNextEvent(display, evt);
if (!peek){
int revert_to;
Window active_win;
XGetInputFocus(display, &active_win, &revert_to);
if (XFilterEvent(evt, active_win)){
//delete evt;
return NULL;
}
}
int type = evt->type;
if (type < 0 || type >= eventProtos->length()) {
char err[50];
sprintf(err, "unknown X event, type = %d", type);
failure(FH, err);
delete evt;
return NULL;
}
oop proto = eventProtos->obj_at(type);
if (!proto->is_proxy()) {
prim_failure(FH, BADTYPEERROR);
delete evt;
return NULL;
}
proxyOop res = proxyOop(proto)->clone();
res->set_pointer(evt);
res->set_type_seal(XEvent_seal);
return res;
}Which generates 0 event, which I fixed by ignoring such events. But still, it doesn't work. When I press the dead key for ´ and then quickly some other key (a for example), it generates garbage, which changes randomly. If I press other key after a while, it just adds the other key.
From „debug printouts“, I can say that it looks like XLookupString_wrap() is called multiple times, or maybe ´ event is still registered, even if it should be ignored.
I don't really understand how Xlib / Self wrapper works, so maybe I am doing something obviously wrong.
|
I was thinking about implementing translation table for keysyms in Self, but decided I will try to do it in C++ Xlib code, because I don't want to replicate functionality, which is already there. I am able to get UTF-8 input for almost* all keys, by modification of https://github.com/russellallen/self/blob/master/objects/glue/xlib_glue.cpp#L448: from: int XLookupString_wrap(XKeyEvent* event, char* string, int len,
objVectorOop keySym) {
KeySym ks;
int n = XLookupString(event, string, len, &ks, NULL);
if (keySym->length() >= 1) keySym->obj_at_put(0, as_smiOop(ks), false);
return n;
}to: XIC getXICContext(XKeyEvent* event){
XIM im = XOpenIM(event->display, NULL, NULL, NULL);
XIC ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, event->window, NULL);
XSetICFocus(ic);
return ic;
}
int XLookupString_wrap(XKeyEvent* event, char* string, int len,
objVectorOop keySym) {
KeySym ks;
int n = Xutf8LookupString(getXICContext(event), event, string, len, &ks, NULL);
if (keySym->length() >= 1)
keySym->obj_at_put(0, as_smiOop(ks), false);
return n;
}It is basically just using Xutf8LookupString instead of *Except combining / dead keys ( oop XNextEvent_wrap(Display *display, bool peek,
objVectorOop eventProtos, void *FH) {
XEvent *evt = new XEvent();
if (peek)
XPeekEvent(display, evt);
else
XNextEvent(display, evt);
int type = evt->type;
if (type < 0 || type >= eventProtos->length()) {
char err[50];
sprintf(err, "unknown X event, type = %d", type);
failure(FH, err);
delete evt;
return NULL;
}
oop proto = eventProtos->obj_at(type);
if (!proto->is_proxy()) {
prim_failure(FH, BADTYPEERROR);
delete evt;
return NULL;
}
proxyOop res = proxyOop(proto)->clone();
res->set_pointer(evt);
res->set_type_seal(XEvent_seal);
return res;
}to: oop XNextEvent_wrap(Display *display, bool peek,
objVectorOop eventProtos, void *FH) {
XEvent *evt = new XEvent();
if (peek)
XPeekEvent(display, evt);
else
XNextEvent(display, evt);
if (!peek){
int revert_to;
Window active_win;
XGetInputFocus(display, &active_win, &revert_to);
if (XFilterEvent(evt, active_win)){
//delete evt;
return NULL;
}
}
int type = evt->type;
if (type < 0 || type >= eventProtos->length()) {
char err[50];
sprintf(err, "unknown X event, type = %d", type);
failure(FH, err);
delete evt;
return NULL;
}
oop proto = eventProtos->obj_at(type);
if (!proto->is_proxy()) {
prim_failure(FH, BADTYPEERROR);
delete evt;
return NULL;
}
proxyOop res = proxyOop(proto)->clone();
res->set_pointer(evt);
res->set_type_seal(XEvent_seal);
return res;
}Which generates From „debug printouts“, I can say that it looks like I don't really understand how Xlib / Self wrapper works, so maybe I am doing something obviously wrong. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
doublec
Apr 30, 2017
Collaborator
Could it be related to the peek event handling? Maybe filter on peek too?
|
Could it be related to the peek event handling? Maybe filter on peek too? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Apr 30, 2017
Contributor
I've tried that, but nope, not related. I am kinda confused by that random output, which looks like it maybe reads pieces of memory which it shouldn't.
|
I've tried that, but nope, not related. I am kinda confused by that random output, which looks like it maybe reads pieces of memory which it shouldn't. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
May 4, 2017
Contributor
I've made some progress and it is almost working now, except when the combining / dead key is pressed with shift.
|
I've made some progress and it is almost working now, except when the combining / dead key is pressed with shift. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Jul 7, 2017
Contributor
So, now when the input works, I am still fighting with output. I didn't put much time into it lately, but I am making slow progress.
I've added new primitive Xutf8DrawString_wrap using primitive maker, which uses Xutf8DrawString instead of XDrawString used so far. Problem is, that Xutf8DrawString is defined as:
void Xutf8DrawString(Display *display, Drawable d, XFontSet font_set, GC gc, int x, int y, char *string, int num_bytes); and XDrawString as
int XDrawString(Display *display, Drawable d, GC gc, int x, int y, char *string, int length); Notice, that Xutf8DrawString is using extra parameter XFontSet font_set. This means, that font is set differently and needs to be passed with each call, which means that I have to add XFontSet structure to Self using primitive maker and also change the Self code which handles setting of font.
|
So, now when the input works, I am still fighting with output. I didn't put much time into it lately, but I am making slow progress. I've added new primitive void Xutf8DrawString(Display *display, Drawable d, XFontSet font_set, GC gc, int x, int y, char *string, int num_bytes); and int XDrawString(Display *display, Drawable d, GC gc, int x, int y, char *string, int length); Notice, that |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
davidungar
Jul 7, 2017
Collaborator
|
Cool! Nice to see this happening.
… On Jul 7, 2017, at 11:05 AM, Bystroushaak ***@***.***> wrote:
So, now when the input works, I am still fighting with output. I didn't put much time into it lately, but I am making slow progress.
I've added new primitive Xutf8DrawString_wrap using primitive maker, which uses Xutf8DrawString instead of XDrawString used so far. Problem is, that Xutf8DrawString is defined as:
void Xutf8DrawString(Display *display, Drawable d, XFontSet font_set, GC gc, int x, int y, char *string, int num_bytes);
and XDrawString as
int XDrawString(Display *display, Drawable d, GC gc, int x, int y, char *string, int length);
Notice, that Xutf8DrawString is using extra parameter XFontSet font_set. This means, that font is set differently and needs to be passed with each call, which means that I have to add XFontSet structure to Self using primitive maker and also change the Self code which handles font's.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#113 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAcJ0NmbcQIKy5Ix9ixWhTq0U8-COc2rks5sLnN8gaJpZM4MGJv7>.
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Bystroushaak
Jul 12, 2017
Contributor
It works as proof of concept as the hack on C++ level. It looks horribly, because of the different unicode fallback font, and aligns strings wrongly, because it still uses XFontStruct to compute width, instead of XFontSet. But it works.
Now I will have to port code to Self and also rewrite Xlib methods for querying the width of string and such to use XFontSet.
|
It works as proof of concept as the hack on C++ level. It looks horribly, because of the different unicode fallback font, and aligns strings wrongly, because it still uses Now I will have to port code to Self and also rewrite Xlib methods for querying the width of string and such to use |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
russellallen
Jul 14, 2017
Owner
This is nice!
Are you still using the original bitmap X font system or the (less ancient) xft?
|
This is nice! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
So far just the original bitmap system. I will look into xft. |


Bystroushaak commentedFeb 20, 2017
Non-ASCII unicode characters ("č" for example) can't be written in the graphic interface. When I press the "č" button on my keyboard, nothing happens.
Also if I read unicode file, it is impossible to show non-ASCII output (garbage occurs instead).
I am aware, that full unicode support in the API would be hard, but input / output should be possible. Right now, it is impossible for me to create usable application in Self, because I can't type into it in my native language.