With the recent changes to libqb.cpp to pull out some of the GLUT logic,
the only actual Objective-C in libqb.cpp was pulled out. That being the
case, it's no longer necessary to have libqb.mm for compiling libqb.cpp,
so we're removing it to simplify the compliation logic a bit.
This fixes all the code so that all the calls to glut functions
happen on the same thread that is running GLUT.
We achieve this by creating a queue of GLUT commands to execute.
Commands can be added to the queue anywhere in the code, and then the
queue is processed on the GLUT thread via it's idle func or timer func.
The command is run and if necessary the result is provided in the
message queue object. Each object contains a completion which can be
waited on to block until the GLUT thread has processed the command.
Fixes: #66
The current GLUT initialization logic is flawed because it allows the
QB64 code portion of the program to start on a separate thread at the
same time that the GLUT code is starting. This results in a race where
some commands won't work for a brief period at the beginning of the
program (with "won't work" being very inconsistent, some return invalid
values, some have a chance at seg faulting).
The same issue also leads to us adding many `while (!window_exists)`
checks in an attempt to solve this race for some of the commands.
Unfortunately this solution is very inconsistently applied leading to
some deadlock situations, and really it's a silly solution when this
race is entirely our creation anyway.
To fix this, the logic was changed such that we perform all of the GLUT
initialization besides calling `glutMainLoop()` before we ever start the
thread that runs the actual QB64 code. By doing it this way we ensure
that the GLUT initialization has already taken place before the code
runs and thus the race is gone.
Things get a bit more interesting with $SCREENHIDE, because that simply
delays the execution of the GLUT initialization indefinitely until
_ScreenShow is done. This was previously very buggy since some commands
rely on FreeGLUT being up and will simply hang the entire program if
run. Other commands have logic to catch this and simply return zero.
The above issue is solved with the `NEEDS_GLUT()` and `OPTIONAL_GLUT()`
macros. Both of them simply check if the GLUT initialization has taken
place and exit the current function if it has not. The difference
between the two is that `NEEDS_GLUT()` throws an 'illegal function call'
error while `OPTIONAL_GLUT()` simply exits with no error. The choice of
behavior of each function was based upon its previous behavior - if it
checked `screen_hide` and exited with no error previously, then
`OPTIONAL_GLUT()` was used. If it deadlocked or similar then
`NEEDS_GLUT()` was used (so instead of deadlocking, it now produces an
error). In this way, programs can now never get stuck due to the use of
`$SCREENHIDE` and all the commands have consistent behavior that can be
relied upon.
Fixes: #234
Fonts 9, 15, and 17 can *only* be used in SCREEN 0. Attempting to use them in graphic screens results in a seg fault and an instant program crash on Windows. This is definitely the most undesirable of behaviors for a program, and can easily be caught and dealt with just by tossing a simple "Illegal Function Call" error for the issue.
Registering a warning function keeps FreeGLUT from writing warnings to
the console (which is not desirable since it conflicts with our own
console output).
Modifies libqb.cpp to add support for opening HTTP connections via
_OPENCLIENT(). This makes use of the libqb_http API in ./libqb, which is
backed by libcurl.
This also includes a bit of refactoring for some of the code that
required additions. I replaced a few of the integer values with enums,
and added a new entry for Http and then implemented it in all the
necessary locations. In addition to `_OPENCLIENT()`, there is also
support for using HTTP connections with `EOF()`, `LOF()`, `GET #`
(variable and fixed length), and `CLOSE`.
I additionally fixed an issue of parsing the colon parts of the
`_OPENCLIENT()` parameter, where having too many colons would cause the
program to crash. Since we only allow so many parts to begin with it I
simply limited the max number of parts it will split to 10.
Fixes: #98
Fixes: #46
This adds the libqb_http API, which is designed to support HTTP and
HTTPS usage from QB64-PE source.
The design consists of a single thread which services all the HTTP(s)
connections. There are then various libqb_http APIs exposed that allow
interacting with this thread to create a new connection, query
connection status, read data, or close the connection.
Internally the thread makes use of the curl_multi interface to allow a
single thread to service multiple HTTP(s) connections in parallel. This
means you can _OPENCLIENT() multiple HTTP connection in a row and all of
them will be serviced at the same time in whatever order data is
available.
HTTP is optional and selected via a Makefile setting. A stub is swapped
in if HTTP support is not used, which avoids need to add another build
flag to libqb.cpp.
We were incorrectly treating the empty string and NULL the same and
using a password dialog for both. It now has the correct behavior of
displaying the password when provided the empty string, but just
displaying a blank input box when provided NULL.
It seems we weren't including stdint.h on Windows by mistake. Likely we
were getting it anywy from some other header, but it sounds like that
got changed in newer versions of MinGW and either way we shouldn't rely
on that.
Being that we include stdint.h on all platforms, I also changed os.h to
always use these types when defining the `int32` and friends sized
types. Ideally we get rid of those defines in the future but we can at
least use the stdint.h types going forward (as we already have).
This applies various dialog settings so that the dialog is always on
top, and also so that Tab works as expected to move between the
controls. The Edit control is moved first so that it's focused when the
window appears.
Currently we have two different ways of determining what Window handle
to tie our dialogs too - we either use GetForegroundWindow(), or create
a completely new and hidden handle. The associated window determines
what process names shows up on notifications, and also which window
can't be interacted with while a dialog is open.
Both of those approaches aren't really good. In the case of
GetForegroundWindow(), it just returns whatever window the user has in
focus, which might be a completely different process. With the hidden
window, it means the dialog and notification aren't really tied to the
QB64-PE program, so you can still interact with the window even when a
dialog is open, and the notification doesn't show an exectuable name.
To solve this we're now using EnumWindows() to enumerate over all the
Windows on the system and find one associated with our ProcessId. We
then check if it's the top-level window and return it if it is.
If that process fails to find a window (such as if this is a
console-only program, or $SCREENHIDE is used) then we check if
GetConsoleWindow() gives us a handle and use that.
If neither approach works, then we fall back to creating a hidden window
so that the dialogs can still work.
I accidentally declared these as uint32_t even though I store -1 in
them. It was working anyway due to the implicit conversion that happens
when adding it to an int32_t, but it should be fixed regardless.
The border color parameter to PAINT is optional, but sub_paint was not
handling that case. What it should do in that situation is keep painting
until it finds pixels that are not the same color as the original
starting pixel was. Instead it would simply assume border color was
valid and paint until it finds color zero (the default parameter value
when it's not provided).
This was originally reported in QB64Official/qb64#2, and Walt
(@TheJoyfulProgrammer) fixed it in QB64Official/qb64#38. Functionally
this is the same change, however I'm checking `passed & 4` to see
whether a border color was provided rather than `bordercol == NULL`.
The later has problems if the provided bordercolor is zero, which is
allowed since zero is a valid color. The `passed` argument indicates
which of the function arguments were actually provided in the QB64
source that called PAINT.
Additionally, along with the `while (true)` loop that Walt changed I
went ahead and removed the duplication of the sections for each
direction. We now just use a couple of arrays to determine which
direction we're checking and loop over all 4.
A function was made unnecessary but wasn't removed, triggering a
warning. Additionally gcc likes parenthesis around `=` assignments used
for conditions.
Fairly simple, this sets the ES_PASSWORD flag when the default text is
blank.
Additionally I fixed the dialog callback to correctly call EndDialog()
rather than DestroyWindow().
These are the last of the quote checks, these don't require any
associated changes as the underlying Win32 functions already allow
quotes. They were simply added to keep parity with the functionality on
other platforms, that that has since been fixed.
This removes the VBS based InputBox for Windows and replaces it with a
version that uses DialogBoxIndirect to create the dialog. While it is a
bit more complicated in some respects, it removes any concerns about the
contents of the strings as they're no longer being inserted into the
generated script.
It also has the advantage that it doesn't spawn another process (which
then shows up in the task bar in some situations).
With this changes quote characters are allowed in all of the parameters.
Escaping the osascript commands requires two layers of escaping: One for the
script itself, and one for the sh arguments.
For the script itself, we simply have to escape the " character with \". When
then take the result of that and escape it sutably for sh arguments in single
quotes. We already have a function for that so we simply call that to do the
job.
Fairly straight forward, the Powershell code was fundimentally just
calling Shell_NotifyIcon under the covers which we can easily do
ourself. The notification has to be tied to a window, so I simply create
a hidden one to use.
A nice improvement here is that instead of having to use the Powershell
icon we can make use of the EXE icon if one was provided. If one is not
provided then we use the default 'application' icon.
tinyfiledialogs had lots of issue surounding the quoting of the
arguments to the dialog functions. The arguments are effectively placed
verbadim into shell commands, and without any proper treatment they
would get accidentally evaluated by the shell, which is a big problem.
Additionally, any arguments containing quotes would just not work since
they would screw up the underlying shell command.
This change fixes all that for Linux. Every argument to the dialog
functions is now surrounded in single quotes, which prevents any
evaluation of the string by the shell. Additionally, because this is
standard the only chracters that need special treatment are the single
quote characters, and proper escaping for them has been added. The
result is that the dialog functions can now accept arguments that hvae
single and double quotes in them (on Linux).
Unfortunately InForm code calls this function directly via
`DECLARE LIBRARY`. For the moment we're adding it back in to keep those
programs functioning, in the future it may be removed.
A quick fix, but providing `DEPENDENCY_CONSOLE_ONLY` when compiling
audio.cpp tells `common.h` to avoid pulling in `freeglut.h`, which fixes
the linking issue.
Fixes: #172
`sub__mousemove` is trying to use `x_scale`, `y_scale`, `x_offset`, and
`y_offset` to calculate where the mouse should be in the event the
window coordinates are different from the screen coordinates.
Unfortunately, all four of those variables are actually never set in the
program. The real scale values and offsets (in the event of
letterboxing) are stored in `environment_2d__` values. This change
switches `sub__mousemove` to simply use the correct values when
calculating the mouse position.
Because `x_scale` and `y_scale` are not used anywhere else I just
removed them completely. I wanted to remove `x_offset` and `y_offset` as
well but there are a few spots that make use of it. It must be a bug,
since they are never assigned values other than zero, but I'm not sure
if the correct fix for the other locations is to use the
`environment_2d__` value or do nothing, so I'm leaving them for now and
we can address them later.
Changing midiaudio.h will make it harder to incorporate new versions
into QB64-PE as they come out. To fix that I have reverted all the
changes to midiaudio.h and moved the few private parts we were using
into a separate 'filepath' API that's part of libqb.
This adds MIDI support to the language as a new unstable feature. There
are two new metacommands that come with this:
$Unstable: Midi
$MidiSoundFont: [Default|"filename"]
The $Unstable command is required to be able to use any of the other
commands, and just signifies that this is not a full part of the
language yet and may change in breaking ways before the API is
finalized.
The $MidiSoundFont command enables MIDI support in the compiled program,
and also specifies what sound font to use to play MIDI files. "Default"
will make use of the soundfont placed at
'./internal/support/default_soundfont.sf2', and otherwise a filename can
be specified to use any soundfont wanted.
In either case, the selected sound font is compiled into the executable
and then loaded at runtime.
Fixes: #115
DPI Awareness allows a program to tell Windows that it will handle
properly scaling itself for the screen's DPI. Thus when a program is DPI
Aware, it will always see the actual screen size. When a program is not
DPI Aware, then Windows will scale the program according to the
selection by the user, and the reported screen size will match the
scaled size rather than the actual screen size.
Commit 189cdb8e added logic to enable DPI Awareness on Windows, but it
was hidden behind a `WINVER` check. This meant it was not actually in
use because at the time QB64 did not set a `WINVER` high enough to
actually enable that code. As such all Windows versions of QB64
including v2.0.2 were not DPI Aware.
Much later-on, Commit 869e361e declared a `_WIN32_WINNT` of `0x0600`,
which seems to have also declared `WINVER` as the same and thus enabled
the DPI Awareness logic. As a consequence, QB64-PE programs no longer
get scaled even though they don't have a way to acquire the current DPI
to do proper scaling themselves.
Since the behavior change was unintentional and proper language support
is not there, we're considering the addition of DPI Awareness a bug. It
will be added back some time later with more language support to allow
it to be properly used.
We started defining `_WIN32_WINNT` a little while ago to express that we
require Windows Vista or above for support. This enables us to access
some Windows Vista-only APIs. The fact that `WINVER` also needs to be
defined was missed, and it seems that defining one means the other no
longer gets defined automatically as it did before. Thus we're simplying
now also defining `WINVER` the same as `_WIN32_WINNT`.
This fixes High-DPI awareness and a few other things that were gated
behind WINVER checks.
- checks all remaining occurrences of the term 'qb64', some remain untouched, some are renamed according to context
- also added new logo for README.md
- this step does finalize the 'Phoenix Edition' re-branding
- replaced default icon image data, which is used, if _ICON is used w/o parameter, but no $EXEICON is specified either (see also Step 1)
- this step completes icon related changes
- int/src/icon.ico (replaced image but same name, dynamically created from given $EXEICON)
- int/src/icon.rc (updated but same name, dynamically created from given $VERSIONINFO)
- int/src/qb64.ico and src/icon.rc removed (not used anymore since dynamic creation was implemented)
- src/qb64.bas updated (rename comes in a later step)
- src/qb64.ico replaced and renamed
We shouldn't allow mutex lock/unlock to silently do nothing if NULL is
passed, as that is very likely a bug. Beyond that the Windows version
doesn't do this, so it's inconsistent as well.
This moves a lot of the preprocessor flags for what compiler/platform
we're using into a libqb-common.h header inside the libqb/include
folder. This gets included at the top of every libqb .cpp file, and is
intended to be fairly small, providing only necessary things like
_WIN32_WINNT (which needs to be defined before including <windows.h> or
friends).
The Buffer API implements an append-only buffer, where you can write to
the end or read from the beginning. Data that is read is discarded from
the buffer, and you can query the buffer to get the current amount of
data inside.
Internally the buffer API is implemented as a chain of separate buffers.
This is done to avoid having to resize the existing buffer, which is
expensive. We keep track of where the reading currently is, and discard
the internal buffers after all the data in them is read.
Completions are basically a oneshot flag, which provide a `wait()` call
that blocks until 'finish()' has been called on the completion.
The nice aspect of completions is that because it is a oneshot the order
does not matter - if 'finish()' is called before 'wait()' then 'wait()'
returns immediately. It makes the logic for waiting until a thread is
done finishing up some work easy to implement.
This adds generic APIs to libqb for handling thread's, mutex's, and
condition variables. On Linux and OSX these are implemented via the ones
provided by pthreads. On Windows they're implemented via the ones
provided by the Win32 API.
For compiling, the code itself is not conditional, but the Makefile
includes logic to decide which implementation to pick.
Note that it would have been nice to simply use std::thread and friends
from C++11, however using them on MinGW appears to be a bit messy. Since
using the Windows ones directly isn't that hard this was an easy compromise.
This sets up a few different flags we'll need for the conditional
compiling, and also sets the C++ standard to gnu++11, which effectively
just matches what we were implicitly using before.
Note: Many files were removed (not yet existing/empty pages). The parser will try to download them on demand and will auto-generate text for missing pages (eg. most _gl pages).
Note: Many files were removed (not yet existing/empty pages). The parser will try to download them on demand and will auto-generate text for missing pages (eg. most _gl pages).
searched.bin was added in error and should not show up when updating
./internal/source.
The symbol files are useless since the coresponding executable is not
something we preserve, and due to them changing practically every build
they result in unnecessary updates of ./internal/source
When building directly from the repo (either from a git clone or a
download of the zip of the repository) the version reported is very
misleading because it will not have a version label, suggesting it is
actually a 'release' version when in fact it could be anything.
The ./.ci/calculate-version.sh logic is already setup to delete an
existing ./internal/version.txt during a detected release build, so we
can just place one in the repositroy and it won't impact the versioning
of CI and release builds, but will show up when building locally.
Fixes: #63
Mostly old build scripts and helper files that are now covered by the
Makefile.
A notable deletion is the glew dll and lib files. These are unnecessary
because we compile `glew.c` directly rather than link against the dll or
lib copies we have.
Having windows call GetSystemMetrics without relying on glutGet, gets rid of the seg fault that can occur at program start up. screenicon was restored to it's previous state so that larger issues with it can be addressed at a future date.
Fixes the issue as brought up on the forums here: https://qb64phoenix.com/forum/showthread.php?tid=408
Also added a small set of logic so we don't end up inside an endless loop if the screen is hidden (via _SCREENHIDE), or if it doesn't exist for whatever reason.
This issue was fixed in 4d61ff79, but due to how ./internal/source is
updated the new ./internal/source files were compiled using a QB64
without the fix, producing files with the wrong quoting. Previously this
was worked around because the build process overwrote these files, but
the `Makefile` build requires them to be fixed.
./internal/source itself is fine, so it's easy enough to simply fix the
files by hand. Since ./internal/source now contains a compiled QB64 that
contains the fix from 4d61ff79 it's generated files will have proper
quoting and won't need to be manually updated.
Currently there is a bug where if a variable width font is in use and
text printed would exactly fit to the end of the row, it is instead
wrapped and printed on the next line.
Ex. You're printing a character that is 10 pixels wide, starting
from position 90 on an image that is 100 pixels wide. This should fix,
but instead your character will be printed on the next line.
The reason this happens is an off by one error, cursor_x (effectively
the X value passed to LOCATE) is one based even when using a variable
width font where cursor_x represents a pixel location. The location that
check if the next character can fit on the screen never handles the base
one, so it ends up treating the ending Y coordinate as one past where it
will actually end, which makes the code thing the print will go past the
edge of the screen.
To fix we simply subtract one before doing the comparison to give us the
actual ending pixel column.
There's no need for all colors to end up with a new prefix for use between $COLOR and $NOPREFIX.
The only conflicts we have are with _Red, _Green, _Blue, so this fix appends a NP_ to the front of the those three color names so they won't conflict with the command names. (NP_ for NoPrefix_)
internal/c/c_compiler no longer contains anything, so git will not
create it. This change makes setup_win.bat create the directory if it's
not already there.
* Create `$NOPREFIX`-friendly version of `color0.bi`
* Create color32_noprefix.bi
* add conditional for noprefix $color
* oh. it was that easy?
* Update CHANGELOG.md
* Update help files [ci-skip]
Co-authored-by: all-other-usernames-were-taken <74026992+all-other-usernames-were-taken@users.noreply.github.com>
Turns out QB64 promises to store all _FLOATs using 32 bytes.
I imagine that is how Galleon planned for eventually storing
larger floating point numbers, but, as it's been observed,
_FLOAT are actually `long double` variables, so they take up
16 bytes. This not a problem for regular variables, but it
does take a toll for arrays, as values are actually stored
as a sequence of 16-byte numbers.
This patch is a hack. But so is FLOAT right now.
The _MEMGET part needs extra work.
m is of type _MEM, but it's never assigned - does that have something to do with it?
Should we have something on the C++ side to access those memory blocks?
In order to allow $DEBUG to work with programs that call CLEAR, the connection handle used to connect to the IDE is locked by default and cannot be CLOSEd. With this change, the debuggee itself can now unlock the handle and close the link.
This reverts commit a94b738407.
It turns out that change stops the SHELL function returning the
child exit code, which is worse than having zombie processes.
This change adds the Program Files and Program Files (x86) folder specifications to the `_DIR$()` function.
`Print _Dir$("program files")
Print _Dir$("program files x86")`
Where the previous bug would only return the console's image size when an image was passed, the new bug made it only ever return 80 for `_Width` and 25 for `_Height` when it should be returning the console's image size if there is no value passed and it is the `_Source`, which it is if we are in a `$Console:Only`.
Here is a code block that demonstrates the bug being fixed:
```Option _Explicit
$Console
Screen _NewImage(640, 480, 32)
_Dest _Console
Width 120, 5
_Dest 0
Print "Hello world"
Print _DesktopWidth, _DesktopHeight
Dim As Long i: i = _NewImage(1280, 720, 32)
Print _Width, _Height
Print _Width(0), _Height(0)
Print _Width(_Console), _Height(_Console)```
When opening a file for random access, if the LEN is not supplied, it defaults the length correctly, but does not allocate the buffer correctly. The code should reference the record_length in the file struct.
The processing for MKDMBF$ fails for numbers smaller than 1. Basic cause is the check for exponent overflow is incorrect. Changed code to correctly check for exponent overflow
2 changes here:
line 13062: When opening a file for random access, if the LEN is not supplied, it defaults the length correctly, but does not allocate the buffer correctly. The code should reference the record_length in the file struct.
Changes in lines 15798-15853: When printing text to the screen, carriage returns in the text are ignored. In sub_file_print, the code for printing to the screen is modified to honor carriage returns.
Fixes a bug that would make QB64 return the incorrect size monitor/desktop size when the resolution is scaled. Also, the last fix I added that set `_Source` to `_Console` automatically caused an issue with `_Width` and `_Height`, causing them to return only the console's image dimensions rather than the image that is passed.