Age | Commit message (Collapse) | Author |
|
Even though it is a fun challange in many ways, I think that,
realistically, it is probably not worth the complexity. The
Prolog backend isn't ANSI-compatible either.
|
|
|
|
|
|
The resource IDs have been changed such that
* the first (least significant) half byte represents the "group",
* the second half byte represents the "subgroup", and
* the third and fourth half bytes uniquely identify the resource
within the group.
Combined with the use of a few helper macros, this makes the message
handling code a lot simpler.
|
|
|
|
This version correctly finds dependencies inside dependencies.
One may wonder why I don't just use gcc -MM c/*.cpp, which produces
basically the same result. The simple reason is that gcc does it very
slowly. It would be unfeasible to run before every compilation.
|
|
|
|
See c6cd2f1.
|
|
|
|
|
|
|
|
|
|
This also fixes an off-by-one error leading to an out-of-bounds write.
|
|
|
|
This reverts much of 97f0a27.
1. It turns out not to be a good idea to resize the list view columns
based on the list view window's own rectangle, as it will change
depending on whether a scrollbar is visible. The problem is that
resizing the columns may add a horizontal scrollbar -- which in
turn may add a vertical scrollbar.
2. The WS_EX_CLIENTEDGE style does not look very good in "modern"
(non-classic) themes. In 97f0a27, I tried solving this by extending
the dimensions of the child windows such that their edges were
hidden. However, this type of overlapping causes problems with the
status bar. My new solution is to instead *reduce* the child
windows' dimensions. This achieves a visual impression similar to
the thicker (more well-designed) edges of the "classically themed"
list view control. To make it look even better, the main window
background is changed from COLOR_WINDOWFRAME (white) to
COLOR_WINDOW (light gray).
|
|
Turns out that SWI-Prolog's wide string functions, which I started
using in 03fe361, do not convert between narrow Prolog atoms and wide
C strings, as I mistakenly thought. Instead, they work with wide
Prolog atoms. In hindsight, it is not surprising.
|
|
|
|
This incidentally removes the need for the variable
template introduced by 21e96c6. I'm sure it will be
needed at some point, though.
|
|
The variable template could be generalized like this:
template <auto F, auto... A> const auto cache = F(A...);
and instantiated like:
cache<GetSystemMetrics, SM_CXVSCROLL>
It would still be limited to constant function arguments, which
usually isn't a problem for GetSystemMetrics, but might be for
other functions.
|
|
It seems that the debug output format changed at some point.
|
|
If you use Emacs, make sure compilation-read-command is t and not nil.
Otherwise, you will be warned when the compile-command variable is
loaded from .dir-locals.el.
|
|
If the main window exists, it is probably a good idea for the message
box to be owned by it. Otherwise, the user may continue to interact
with the main window. Of course, that could sometimes be a benefit,
but it SEEMS a bit unsafe... I might change this in the future.
|
|
Not quite so awful anymore.
|
|
No, not "awful", AWFUN!
Speaking of AWFUN, here is an alternative implementation of it:
#define AWFUN(t, f) cond_fun<t, f##A, f##W>
template <typename T, auto F, auto G>
std::enable_if_t<std::is_same_v<T, char>, decltype(F)> cond_fun = F;
template <auto F, auto G>
auto cond_fun<wchar_t, F, G> = G;
This implementation uses a variable template instead of a function
template, but I decided against it, as (at least I think) it would
instantiate useless variables that merely point to pre-existing API
functions. Like,
auto cond_fun__wchar_t__blablabla = MessageBoxW;
auto cond_fun__char__blablabla = MessageBoxA;
which is quite useless. Better to just have a constexpr function,
which the compiler may inline, return the real function pointer.
|
|
As the message box has no owner (because the main window may not be
initialized yet), it may be unclear which application is being
terminated.
|
|
|
|
|
|
|
|
This improves upon 79d4fa6.
Actually, ANSI compatibility may be desirable, as recent work has been
done to make the A versions of Windows API functions work with UTF-8.
|
|
It's not very useful, but it's a fun exercise.
|
|
|
|
|
|
In warn_nil, the return value was undefined on exception -- I think.
While informative, the names throw_nil and warn_nil don't work very
well in conditionals:
if (warn_nil<f>(...)) g();
sounds like g should be called if f returns nil and a warning is
issued. But it is actually the other way around; g is called if f is
successful.
if (prefer<f>(...)) g();
sounds less like that.
|
|
|
|
This is equivalent, but it may be useful to highlight that `args' does
not HAVE to be declared in order to get the return type of the
function call.
|
|
|
|
Some of the checks are likely redundant, but the Windows API
documentation rarely makes it clear WHICH errors may be returned (and
under which circumstances) rather than simply WHETHER errors may be
returned (under any circumstances, including those that do not apply
in the given case).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Speaking of unclear documentation, it is not obvious whether it is
necessary for programs calling into Prolog to manually mark and
release strings. I suppose that it should be, if the same logic that
applies to terms apply to strings.
On the other hand, the stack in which the strings are stored belongs
to Prolog, and there is nothing that would prevent Prolog from
cleaning up the strings when called at a later time. I am not sure.
But better safe than sorry, I guess.
The Mark class acts like the Frame class. The constructor and
destructor are equivalent to the PL_STRINGS_MARK and
PL_STRINGS_RELEASE macros.
Unlike for 34c3280, I did not notice any differences in memory usage
after this change. Perhaps that is because it has no effect; perhaps
it is because Prolog's stack is very big.
|
|
Apparently foreign frames ARE needed when calling Prolog from C. The
official documentation is very terse and could make this clearer.
To summarize, whenever a term is created (e.g., PL_new_term_refs), its
reference count is increased by one. It is garbage-collected when its
reference count hits zero. But the reference count is never decreased
unless (a) control returns to Prolog after executing a foreign
predicate -- which does not happen in my application -- or (b) the
foreign frame in which the term was created is closed.
In other words, terms must be created within a foreign frame. This is
achieved by initializing a Frame object before creating the term and
destroying it once the term has served its purpose.
The destructor for Frame does not DISCARD the frame, only CLOSE it.
The former would also invalidate all data bound by the terms, which is
usually undesirable.
|
|
|
|
It isn't really more safe, but it removes the need for a confusing
function pointer cast, which is easy to get wrong. As far as the
compiler is concerned, the result is literally the same, but it does
force the caller to (indirectly, via the template parameter) cast the
return value, which may be a good thing.
|
|
|
|
|
|
|