Merge pull request #17 from hdon/master

Fix some crashes, OpenGL context sharing, and other minor changes
This commit is contained in:
Vadim Lopatin 2014-09-02 10:53:11 +04:00
commit b26673372d
11 changed files with 352 additions and 258 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ bin
*.obj *.obj
*.~* *.~*
*.*~ *.*~
.*.sw*

View File

@ -94,21 +94,17 @@ struct UIString {
alias value this; alias value this;
} }
public __gshared UIStringTranslator i18n = new UIStringTranslator(); shared UIStringTranslator i18n;
//static shared this() { shared static this() {
// i18n = new UIStringTranslator(); i18n = new shared UIStringTranslator();
//} }
class UIStringTranslator { synchronized class UIStringTranslator {
private UIStringList _main; private UIStringList _main;
private UIStringList _fallback; private UIStringList _fallback;
private string[] _resourceDirs; private string[] _resourceDirs;
/// get i18n resource directory
@property string[] resourceDirs() { return _resourceDirs; }
/// set i18n resource directory
@property void resourceDirs(string[] dirs) { _resourceDirs = dirs; }
/// looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from /// looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from
string[] findTranslationsDir(string[] dirs ...) { void findTranslationsDir(string[] dirs ...) {
_resourceDirs.length = 0; _resourceDirs.length = 0;
import std.file; import std.file;
foreach(dir; dirs) { foreach(dir; dirs) {
@ -118,7 +114,6 @@ class UIStringTranslator {
_resourceDirs ~= path; _resourceDirs ~= path;
} }
} }
return _resourceDirs;
} }
/// convert resource path - append resource dir if necessary /// convert resource path - append resource dir if necessary
@ -140,8 +135,8 @@ class UIStringTranslator {
} }
this() { this() {
_main = new UIStringList(); _main = new shared UIStringList();
_fallback = new UIStringList(); _fallback = new shared UIStringList();
} }
/// load translation file(s) /// load translation file(s)
bool load(string mainFilename, string fallbackFilename = null) { bool load(string mainFilename, string fallbackFilename = null) {
@ -168,7 +163,7 @@ class UIStringTranslator {
} }
/// UI string translator /// UI string translator
class UIStringList { private shared class UIStringList {
private dstring[string] _map; private dstring[string] _map;
/// remove all items /// remove all items
void clear() { void clear() {

View File

@ -39,31 +39,32 @@ enum LogLevel : int {
Trace Trace
} }
__gshared LogLevel logLevel = LogLevel.Info;
__gshared std.stdio.File logFile;
void setLogLevel(LogLevel level) {
logLevel = level;
}
long currentTimeMillis() { long currentTimeMillis() {
return std.datetime.Clock.currStdTime / 10000; return std.datetime.Clock.currStdTime / 10000;
} }
void setStdoutLogger() { synchronized class Log {
static {
private LogLevel logLevel = LogLevel.Info;
private std.stdio.File logFile;
void setStdoutLogger() {
logFile = stdout; logFile = stdout;
} }
void setStderrLogger() { void setStderrLogger() {
logFile = stderr; logFile = stderr;
} }
void setFileLogger(File file) { void setFileLogger(File file) {
logFile = file; logFile = file;
} }
class Log { void setLogLevel(LogLevel level) {
static string logLevelName(LogLevel level) { logLevel = level;
}
string logLevelName(LogLevel level) {
switch (level) { switch (level) {
case LogLevel.Fatal: return "F"; case LogLevel.Fatal: return "F";
case LogLevel.Error: return "E"; case LogLevel.Error: return "E";
@ -74,7 +75,7 @@ class Log {
default: return "?"; default: return "?";
} }
} }
static void log(S...)(LogLevel level, S args) { void log(S...)(LogLevel level, S args) {
if (logLevel >= level && logFile.isOpen) { if (logLevel >= level && logFile.isOpen) {
SysTime ts = Clock.currTime(); SysTime ts = Clock.currTime();
logFile.writef("%04d-%02d-%02d %02d:%02d:%02d.%03d %s ", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fracSec.msecs, logLevelName(level)); logFile.writef("%04d-%02d-%02d %02d:%02d:%02d.%03d %s ", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fracSec.msecs, logLevelName(level));
@ -82,28 +83,29 @@ class Log {
logFile.flush(); logFile.flush();
} }
} }
static void v(S...)(S args) { void v(S...)(S args) {
if (logLevel >= LogLevel.Trace && logFile.isOpen) if (logLevel >= LogLevel.Trace && logFile.isOpen)
log(LogLevel.Trace, args); log(LogLevel.Trace, args);
} }
static void d(S...)(S args) { void d(S...)(S args) {
if (logLevel >= LogLevel.Debug && logFile.isOpen) if (logLevel >= LogLevel.Debug && logFile.isOpen)
log(LogLevel.Debug, args); log(LogLevel.Debug, args);
} }
static void i(S...)(S args) { void i(S...)(S args) {
if (logLevel >= LogLevel.Info && logFile.isOpen) if (logLevel >= LogLevel.Info && logFile.isOpen)
log(LogLevel.Info, args); log(LogLevel.Info, args);
} }
static void w(S...)(S args) { void w(S...)(S args) {
if (logLevel >= LogLevel.Warn && logFile.isOpen) if (logLevel >= LogLevel.Warn && logFile.isOpen)
log(LogLevel.Warn, args); log(LogLevel.Warn, args);
} }
static void e(S...)(S args) { void e(S...)(S args) {
if (logLevel >= LogLevel.Error && logFile.isOpen) if (logLevel >= LogLevel.Error && logFile.isOpen)
log(LogLevel.Error, args); log(LogLevel.Error, args);
} }
static void f(S...)(S args) { void f(S...)(S args) {
if (logLevel >= LogLevel.Fatal && logFile.isOpen) if (logLevel >= LogLevel.Fatal && logFile.isOpen)
log(LogLevel.Fatal, args); log(LogLevel.Fatal, args);
} }
}
} }

View File

@ -32,15 +32,27 @@ enum StandardAction : int {
Save, Save,
} }
__gshared const Action ACTION_OK = new Action(StandardAction.Ok, "ACTION_OK"c); immutable Action ACTION_OK;
__gshared const Action ACTION_CANCEL = new Action(StandardAction.Cancel, "ACTION_CANCEL"c); immutable Action ACTION_CANCEL;
__gshared const Action ACTION_YES = new Action(StandardAction.Yes, "ACTION_YES"c); immutable Action ACTION_YES;
__gshared const Action ACTION_NO = new Action(StandardAction.No, "ACTION_NO"c); immutable Action ACTION_NO;
__gshared const Action ACTION_CLOSE = new Action(StandardAction.Close, "ACTION_CLOSE"c); immutable Action ACTION_CLOSE;
__gshared const Action ACTION_ABORT = new Action(StandardAction.Abort, "ACTION_ABORT"c); immutable Action ACTION_ABORT;
__gshared const Action ACTION_RETRY = new Action(StandardAction.Retry, "ACTION_RETRY"c); immutable Action ACTION_RETRY;
__gshared const Action ACTION_IGNORE = new Action(StandardAction.Ignore, "ACTION_IGNORE"c); immutable Action ACTION_IGNORE;
__gshared const Action ACTION_OPEN = new Action(StandardAction.Open, "ACTION_OPEN"c); immutable Action ACTION_OPEN;
__gshared const Action ACTION_SAVE = new Action(StandardAction.Save, "ACTION_SAVE"c); immutable Action ACTION_SAVE;
static this()
{
ACTION_OK = cast(immutable(Action)) new Action(StandardAction.Ok, "ACTION_OK"c);
ACTION_CANCEL = cast(immutable(Action)) new Action(StandardAction.Cancel, "ACTION_CANCEL"c);
ACTION_YES = cast(immutable(Action)) new Action(StandardAction.Yes, "ACTION_YES"c);
ACTION_NO = cast(immutable(Action)) new Action(StandardAction.No, "ACTION_NO"c);
ACTION_CLOSE = cast(immutable(Action)) new Action(StandardAction.Close, "ACTION_CLOSE"c);
ACTION_ABORT = cast(immutable(Action)) new Action(StandardAction.Abort, "ACTION_ABORT"c);
ACTION_RETRY = cast(immutable(Action)) new Action(StandardAction.Retry, "ACTION_RETRY"c);
ACTION_IGNORE = cast(immutable(Action)) new Action(StandardAction.Ignore, "ACTION_IGNORE"c);
ACTION_OPEN = cast(immutable(Action)) new Action(StandardAction.Open, "ACTION_OPEN"c);
ACTION_SAVE = cast(immutable(Action)) new Action(StandardAction.Save, "ACTION_SAVE"c);
}

View File

@ -39,12 +39,28 @@ private void LVGLFillColor(uint color, float * buf, int count) {
} }
} }
/// for OpenGL calls diagnostics. /* For reporting OpenGL errors, it's nicer to get a human-readable symbolic name for the
private bool checkError(string context, string file = __FILE__, int line = __LINE__) { * error instead of the numeric form. Derelict's GLenum is just an alias for uint, so we
int err = glGetError(); * can't depend on D's nice toString() for enums.
if (err != GL_NO_ERROR) { */
//string errorString = fromStringz(gluErrorString()); private immutable(string[int]) errors;
Log.e("OpenGL error ", err, " at ", file, ":", line, " -- ", context); static this() {
errors = [
0x0500: "GL_INVALID_ENUM",
0x0501: "GL_INVALID_VALUE",
0x0502: "GL_INVALID_OPERATION",
0x0505: "GL_OUT_OF_MEMORY"
];
}
/* Convenient wrapper around glGetError()
* TODO use one of the DEBUG extensions instead
*/
bool checkError(string context="", string file=__FILE__, int line=__LINE__)
{
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
Log.e("OpenGL error ", err in errors ? errors[err] : to!string(err), " at ", file, ":", line, " -- ", context);
return true; return true;
} }
return false; return false;
@ -526,14 +542,36 @@ class SolidFillProgram : GLProgram {
return false; return false;
beforeExecute(); beforeExecute();
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(
GL_ARRAY_BUFFER,
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
null,
GL_STREAM_DRAW);
glBufferSubData(
GL_ARRAY_BUFFER,
0,
vertices.length * vertices[0].sizeof,
vertices.ptr);
glBufferSubData(
GL_ARRAY_BUFFER,
vertices.length * vertices[0].sizeof,
colors.length * colors[0].sizeof, colors.ptr);
glEnableVertexAttribArray(vertexLocation); glEnableVertexAttribArray(vertexLocation);
checkError("glEnableVertexAttribArray"); checkError("glEnableVertexAttribArray");
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, float.sizeof * 3, vertices.ptr); glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
checkError("glVertexAttribPointer"); checkError("glVertexAttribPointer");
glEnableVertexAttribArray(colAttrLocation); glEnableVertexAttribArray(colAttrLocation);
checkError("glEnableVertexAttribArray"); checkError("glEnableVertexAttribArray");
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, float.sizeof * 4, colors.ptr); glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*6));
checkError("glVertexAttribPointer"); checkError("glVertexAttribPointer");
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
@ -545,6 +583,12 @@ class SolidFillProgram : GLProgram {
checkError("glDisableVertexAttribArray"); checkError("glDisableVertexAttribArray");
afterExecute(); afterExecute();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
return true; return true;
} }
} }
@ -600,13 +644,43 @@ class TextureProgram : SolidFillProgram {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
checkError("drawColorAndTextureRect - glTexParameteri"); checkError("drawColorAndTextureRect - glTexParameteri");
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(
GL_ARRAY_BUFFER,
vertices.length * vertices[0].sizeof +
colors.length * colors[0].sizeof +
texcoords.length * texcoords[0].sizeof,
null,
GL_STREAM_DRAW);
glBufferSubData(
GL_ARRAY_BUFFER,
0,
vertices.length * vertices[0].sizeof,
vertices.ptr);
glBufferSubData(
GL_ARRAY_BUFFER,
vertices.length * vertices[0].sizeof,
colors.length * colors[0].sizeof,
colors.ptr);
glBufferSubData(
GL_ARRAY_BUFFER,
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
texcoords.length * texcoords[0].sizeof,
texcoords.ptr);
glEnableVertexAttribArray(vertexLocation); glEnableVertexAttribArray(vertexLocation);
glEnableVertexAttribArray(colAttrLocation); glEnableVertexAttribArray(colAttrLocation);
glEnableVertexAttribArray(texCoordLocation); glEnableVertexAttribArray(texCoordLocation);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices.ptr); glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.ptr); glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof));
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords.ptr); glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof));
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
checkError("glDrawArrays"); checkError("glDrawArrays");
@ -616,6 +690,13 @@ class TextureProgram : SolidFillProgram {
glDisableVertexAttribArray(texCoordLocation); glDisableVertexAttribArray(texCoordLocation);
afterExecute(); afterExecute();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
checkError("glBindTexture"); checkError("glBindTexture");
return true; return true;

View File

@ -26,6 +26,7 @@ import dlangui.core.logger;
import dlangui.core.types; import dlangui.core.types;
import dlangui.graphics.drawbuf; import dlangui.graphics.drawbuf;
import std.stream; import std.stream;
import std.conv : to;
/// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed /// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed
ColorDrawBuf loadImage(string filename) { ColorDrawBuf loadImage(string filename) {
@ -36,6 +37,7 @@ ColorDrawBuf loadImage(string filename) {
return loadImage(f); return loadImage(f);
} catch (Exception e) { } catch (Exception e) {
Log.e("exception while loading image from file ", filename); Log.e("exception while loading image from file ", filename);
Log.e(to!string(e));
return null; return null;
} }
} }

View File

@ -984,7 +984,7 @@ version(USE_SDL) {
int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{ {
setFileLogger(std.stdio.File("ui.log", "w")); setFileLogger(std.stdio.File("ui.log", "w"));
setLogLevel(LogLevel.Trace); Log.setLogLevel(LogLevel.Trace);
Log.d("myWinMain()"); Log.d("myWinMain()");
string basePath = exePath(); string basePath = exePath();
Log.i("Current executable: ", exePath()); Log.i("Current executable: ", exePath());
@ -1006,8 +1006,8 @@ version(USE_SDL) {
int main(string[] args) int main(string[] args)
{ {
setStderrLogger(); Log.setStderrLogger();
setLogLevel(LogLevel.Trace); Log.setLogLevel(LogLevel.Warn);
FreeTypeFontManager ft = new FreeTypeFontManager(); FreeTypeFontManager ft = new FreeTypeFontManager();
@ -1054,6 +1054,8 @@ version(USE_SDL) {
// Set OpenGL attributes // Set OpenGL attributes
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
// Share textures between contexts
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
} }
SDLPlatform sdl = new SDLPlatform(); SDLPlatform sdl = new SDLPlatform();

View File

@ -721,9 +721,9 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
{ {
setFileLogger(std.stdio.File("ui.log", "w")); setFileLogger(std.stdio.File("ui.log", "w"));
debug { debug {
setLogLevel(LogLevel.Trace); Log.setLogLevel(LogLevel.Trace);
} else { } else {
setLogLevel(LogLevel.Info); Log.setLogLevel(LogLevel.Info);
} }
Log.d("myWinMain()"); Log.d("myWinMain()");
string basePath = exePath(); string basePath = exePath();

View File

@ -1131,7 +1131,7 @@ version(USE_XCB) {
{ {
setStderrLogger(); setStderrLogger();
setLogLevel(LogLevel.Trace); Log.setLogLevel(LogLevel.Trace);
FreeTypeFontManager ft = new FreeTypeFontManager(); FreeTypeFontManager ft = new FreeTypeFontManager();
ft.registerFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FontFamily.SansSerif, "DejaVu", false, FontWeight.Normal); ft.registerFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FontFamily.SansSerif, "DejaVu", false, FontWeight.Normal);

View File

@ -946,14 +946,14 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
bool isHeader = x < _headerCols || y < _headerRows; bool isHeader = x < _headerCols || y < _headerRows;
if (phase == 0) { if (phase == 0) {
if (isHeader) if (isHeader)
drawHeaderCellBackground(buf, cellRect, x - _headerCols, y - _headerRows); drawHeaderCellBackground(buf, buf.clipRect, x - _headerCols, y - _headerRows);
else else
drawCellBackground(buf, cellRect, x - _headerCols, y - _headerRows); drawCellBackground(buf, buf.clipRect, x - _headerCols, y - _headerRows);
} else { } else {
if (isHeader) if (isHeader)
drawHeaderCell(buf, cellRect, x - _headerCols, y - _headerRows); drawHeaderCell(buf, buf.clipRect, x - _headerCols, y - _headerRows);
else else
drawCell(buf, cellRect, x - _headerCols, y - _headerRows); drawCell(buf, buf.clipRect, x - _headerCols, y - _headerRows);
} }
} }
} }

View File

@ -527,13 +527,12 @@ class MenuWidgetBase : ListWidget {
// copy item action listeners // copy item action listeners
Signal!MenuItemActionHandler onMenuItemActionListenerCopy = onMenuItemActionListener; Signal!MenuItemActionHandler onMenuItemActionListenerCopy = onMenuItemActionListener;
handleMenuItemClick(item);
PopupWidget popup = cast(PopupWidget)parent; PopupWidget popup = cast(PopupWidget)parent;
if (popup) if (popup)
popup.close(); popup.close();
handleMenuItemClick(item);
// this pointer now can be invalid - if popup removed // this pointer now can be invalid - if popup removed
if (onMenuItemClickListenerCopy.assigned) if (onMenuItemClickListenerCopy.assigned)
if (onMenuItemClickListenerCopy(item)) if (onMenuItemClickListenerCopy(item))