2016/06/10 - V1.01b released! Fix to Installer - Download now! Click Here!
|
Fixing Benkyou Studio for use on linux in Mono!
While I am currently still primarily a windows user, it is my intention to migrate to Linux
I use Linux for my web-browsing, but at the moment most of my development skills are windows based
So, I was looking to see to what extent my study tool Benkyou Studio could be used within Linux
This was especially important, as I had to buy a Win10 tablet soley to use the study tool - so
it was currently restricting my platform choices - and at this stage a total rewrite to Andoid
or Java is out the question.
So, the options for Linux
The program loaded in Wine, but there were a lot of layout issues, more worryingly there was
Mojibake - scrambled symbols as if Linux was converting the japanese symbols wrongly, as
I was leaving this 100% to the .Net framework - so I ruled Wine out of the game for now.
Mono was a different kettle of fish.
Building had a slight issue, as Linux couldn't support the speech synthesis I use, no problem
I'll just disable it for now with Compiler statements
#if !LINUX
using SpeechLib;
#endif
I declare LINUX during compile, and with a few of these compiler conditionals in the right places
the program compiles with Xbuild just fine - a good start!
Now, thats as far as things went well, as Out of memory errors started firing up before anything
happened... I opened the project up in the excellent MonoDevelop - which seemed to open everything
fine (and equally incredibly - did not alter any of the files in a way Visual studio did not like
- so I can open the same files on both)
Anyway, it turns out there is something weird about the System.Drawing.Image.FromFile() command
, it appears it leaves its files open! I read this online and assumed it was a mistake, but I since
- due to a mistake of reinstalling over the open program - it seems to be true, files that were opened
by the program are still in use after they have no place being!?!
Swapping:
return System.Drawing.Image.FromFile(filename);
For:
Stream sr =new FileStream(filename,FileMode.Open);
System.Drawing.Image im= System.Drawing.Image.FromStream(sr);
sr.Close();
sr=null;
return im;
Fixed the problem, both for linux crashing and windows keeping its files open! great stuff!
So whats next.. well, the big killer is windows paths - all my paths are relative,
eg res\img\img1.png , so I didn't have to worry about c:\ or anything, but linux doesnt like
\ symbols in the path, it needs / - whereas weirdly .net on windows is happy with either.
Also Windows is not case sensitive, but linux is - a big problem! even bigger since my program
is designed to use user developed scripts - even if I keep my case constant, other users may not
so what to do?
Well, the solution I found was to write a "pathfixer"... what does it do? well
it makes all / and \ symbols the correct one for the current machine, also it goes through the path
bit by bit, and looks at all subfolders for one that matches - irrespectively of case - then returns
the "Case corrected" version of the path back
In short, I can give my "PathFix" function a windows path with \ symbols and the wrong case in the path and filenames
and it will give me the linus / symbols, and the correct case - assuming the file really exists! - putting this in all the places in
my code that looks for a file fixed all the path case problems in one go!!!
Here is the code!
public static string slash = Path.DirectorySeparatorChar.ToString();
public static bool exists(string lin) {
return System.IO.File.Exists(PathFix(lin));
}
public static bool IsLinux // found this online, it detects if current os is linux
{
get
{
int p = (int)Environment.OSVersion.Platform;
return (p == 4) || (p == 6) || (p == 128);
}
}
public static string PathFix(string lin) {
// right now this is a fix only for linux
// It switches slash symbols, and corrects case of folders and files
if (!IsLinux) return lin;
if (slash == "/")
{
lin= lin.Replace("\\", slash);
}
else {
lin = lin.Replace("/", slash);
}
string buildup = "";
int ii = ss.CountItems(lin, slash);
for (int i = 0; i <= ii; i++)
{
if (i < ii) {
buildup = PathFixDir(buildup, ss.GetItem(lin, slash, i));
} else {
buildup = PathFixFile(buildup, ss.GetItem(lin, slash, i));
}
}
return buildup;
}
public static string PathFixDir(string path, string lookfor)
{
if (lookfor.Length == 0) return slash;
string path2 = "";
if (path.Length > 0)
{
if (VbX.Right(path, 1) != slash) path += slash;
path2 = path;
}
else {
path2 = "." + slash;
}
foreach (string dir in Directory.GetDirectories(path2)){
if (dir.ToLower() == path+lookfor.ToLower()) return dir;
}
if (path.Length > 0) lookfor = path + slash + lookfor;
return lookfor;
}
public static string PathFixFile(string path, string lookfor)
{
string path2 = "";
if (path.Length > 0)
{
if (VbX.Right(path, 1) != slash) path += slash;
path2 = path;
}
else
{
path2 = "." + slash;
}
try{
foreach (string dir in Directory.GetFiles(path2))
{
if (dir.ToLower() == path + lookfor.ToLower()) return dir;
}
} catch (Exception ex){
}
return path + lookfor;
}
So almost all done as everything now works, however my icons looked kinda weird still, now, my code automatically recolours
the icons with the theme color and after a bit of messing, it seems I have to "Premultiply"
the alpha, adding just one line of code fixed the problem!
if (lnx.IsLinux) {R = R * A / 255;G = G * A / 255;B = B * A / 255;}
the R G and B colours could now be used to set the pixel value, and everything worked as on windows.
With all these tricks combined, the same code works on Windows and Linux (except text to speech)
Most impressive of all the whole "Conversion" job only took about three hours!
Excellent stuff!
Here's a picture of the software working on PcLinuxOs!