minigui - make dialog/message boxes less bad

by setting them correctly as transient to their originator window, the
window manager can place them better and set the focus as expected
automatically
This commit is contained in:
Adam D. Ruppe 2024-09-29 21:14:40 -04:00
parent 115be86c63
commit fc4d833235
4 changed files with 197 additions and 46 deletions

213
minigui.d
View file

@ -4069,7 +4069,7 @@ class DataControllerWidget(T) : WidgetContainer {
static if(is(typeof(__traits(getMember, this.datum, member)) == function)) { static if(is(typeof(__traits(getMember, this.datum, member)) == function)) {
w.addEventListener("triggered", delegate() { w.addEventListener("triggered", delegate() {
makeAutomaticHandler!(__traits(getMember, this.datum, member))(&__traits(getMember, this.datum, member))(); makeAutomaticHandler!(__traits(getMember, this.datum, member))(this.parentWindow, &__traits(getMember, this.datum, member))();
notifyDataUpdated(); notifyDataUpdated();
}); });
} else static if(is(typeof(w.isChecked) == bool)) { } else static if(is(typeof(w.isChecked) == bool)) {
@ -8047,7 +8047,8 @@ class Window : Widget {
assert(mouseCapturedBy is null || byWhom is mouseCapturedBy); assert(mouseCapturedBy is null || byWhom is mouseCapturedBy);
mouseCaptureCount++; mouseCaptureCount++;
mouseCapturedBy = byWhom; mouseCapturedBy = byWhom;
win.grabInput(); win.grabInput(false, true, false);
//void grabInput(bool keyboard = true, bool mouse = true, bool confine = false) {
} }
void releaseMouseCapture() { void releaseMouseCapture() {
mouseCaptureCount--; mouseCaptureCount--;
@ -8055,6 +8056,20 @@ class Window : Widget {
win.releaseInputGrab(); win.releaseInputGrab();
} }
/++
+/
MessageBoxButton messageBox(string title, string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
return .messageBox(this, title, message, style, icon);
}
/// ditto
int messageBox(string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
return messageBox(null, message, style, icon);
}
/++ /++
Sets the window icon which is often seen in title bars and taskbars. Sets the window icon which is often seen in title bars and taskbars.
@ -8427,15 +8442,16 @@ class Window : Widget {
The width and height arguments were added to the overload that takes `string` first on June 21, 2021. The width and height arguments were added to the overload that takes `string` first on June 21, 2021.
+/ +/
this(int width = 500, int height = 500, string title = null) { this(int width = 500, int height = 500, string title = null, WindowTypes windowType = WindowTypes.normal, WindowFlags windowFlags = WindowFlags.dontAutoShow | WindowFlags.managesChildWindowFocus, SimpleWindow parent = null) {
if(title is null) { if(title is null) {
import core.runtime; import core.runtime;
if(Runtime.args.length) if(Runtime.args.length)
title = Runtime.args[0]; title = Runtime.args[0];
} }
win = new SimpleWindow(width, height, title, OpenGlOptions.no, Resizability.allowResizing, WindowTypes.normal, WindowFlags.dontAutoShow | WindowFlags.managesChildWindowFocus); win = new SimpleWindow(width, height, title, OpenGlOptions.no, Resizability.allowResizing, windowType, windowFlags, parent);
static if(UsingSimpledisplayX11) { static if(UsingSimpledisplayX11)
if(windowFlags & WindowFlags.managesChildWindowFocus) {
///+ ///+
// for input proxy // for input proxy
auto display = XDisplayConnection.get; auto display = XDisplayConnection.get;
@ -8879,14 +8895,28 @@ debug private class DevToolWindow : Window {
A dialog is a transient window that intends to get information from A dialog is a transient window that intends to get information from
the user before being dismissed. the user before being dismissed.
+/ +/
abstract class Dialog : Window { class Dialog : Window {
/// ///
this(int width, int height, string title = null) { this(Window parent, int width, int height, string title = null) {
super(width, height, title); super(width, height, title, WindowTypes.dialog, WindowFlags.dontAutoShow | WindowFlags.transient, parent is null ? null : parent.win);
// this(int width = 500, int height = 500, string title = null, WindowTypes windowType = WindowTypes.normal, WindowFlags windowFlags = WindowFlags.dontAutoShow | WindowFlags.managesChildWindowFocus, SimpleWindow parent = null) {
} }
/// ///
abstract void OK(); this(Window parent, string title, int width, int height) {
this(parent, width, height, title);
}
deprecated("Pass an explicit parent window, even if it is `null`")
this(int width, int height, string title = null) {
this(null, width, height, title);
}
///
void OK() {
}
/// ///
void Cancel() { void Cancel() {
@ -9767,7 +9797,7 @@ private void autoExceptionHandler(Exception e) {
messageBox(e.msg); messageBox(e.msg);
} }
private void delegate() makeAutomaticHandler(alias fn, T)(T t) { private void delegate() makeAutomaticHandler(alias fn, T)(Window window, T t) {
static if(is(T : void delegate())) { static if(is(T : void delegate())) {
return () { return () {
try try
@ -9790,9 +9820,9 @@ private void delegate() makeAutomaticHandler(alias fn, T)(T t) {
(type == FileDialogType.Automatic && (__traits(identifier, fn).startsWith("Save") || __traits(identifier, fn).startsWith("Export"))) (type == FileDialogType.Automatic && (__traits(identifier, fn).startsWith("Save") || __traits(identifier, fn).startsWith("Export")))
|| type == FileDialogType.Save) || type == FileDialogType.Save)
{ {
getSaveFileName(&onOK, member, filters, null); getSaveFileName(window, &onOK, member, filters, null);
} else } else
getOpenFileName(&onOK, member, filters, null); getOpenFileName(window, &onOK, member, filters, null);
}; };
} else { } else {
struct S { struct S {
@ -9805,7 +9835,7 @@ private void delegate() makeAutomaticHandler(alias fn, T)(T t) {
}); });
} }
return () { return () {
dialog((S s) { dialog(window, (S s) {
try { try {
static if(is(typeof(t) Ret == return)) { static if(is(typeof(t) Ret == return)) {
static if(is(Ret == void)) { static if(is(Ret == void)) {
@ -9962,7 +9992,7 @@ class MainWindow : Window {
if(label.length == 0) if(label.length == 0)
label = memberName.toMenuLabel; label = memberName.toMenuLabel;
auto handler = makeAutomaticHandler!(__traits(getMember, T, memberName))(&__traits(getMember, t, memberName)); auto handler = makeAutomaticHandler!(__traits(getMember, T, memberName))(this.parentWindow, &__traits(getMember, t, memberName));
auto action = new Action(label, correctIcon, handler); auto action = new Action(label, correctIcon, handler);
@ -13436,16 +13466,25 @@ class RichTextDisplay : Widget {
+/ +/
class TextDisplay : EditableTextWidget { class TextDisplay : EditableTextWidget {
this(string text, Widget parent) { this(string text, Widget parent) {
super(parent); super(true, parent);
this.content = text; this.content = text;
} }
override int maxHeight() { return int.max; } override int maxHeight() { return int.max; }
override int minHeight() { return 50; } override int minHeight() { return Window.defaultLineHeight; }
override int heightStretchiness() { return 7; } override int heightStretchiness() { return 7; }
override int heightShrinkiness() { return 2; }
override int flexBasisWidth() { return 250; } override int flexBasisWidth() {
override int flexBasisHeight() { return 50; } return scaleWithDpi(250);
}
override int flexBasisHeight() {
if(textLayout is null || this.tdh is null)
return Window.defaultLineHeight;
auto textHeight = borderBoxForContentBox(Rectangle(Point(0, 0), Size(0, textLayout.height))).height;
return this.tdh.borderBoxForContentBox(Rectangle(Point(0, 0), Size(0, textHeight))).height;
}
override TextDisplayHelper textDisplayHelperFactory(TextLayouter textLayout, ScrollMessageWidget smw) { override TextDisplayHelper textDisplayHelperFactory(TextLayouter textLayout, ScrollMessageWidget smw) {
return new MyTextDisplayHelper(textLayout, smw); return new MyTextDisplayHelper(textLayout, smw);
@ -13737,13 +13776,44 @@ private class GenericListViewWidgetInner : Widget {
/// /++
class MessageBox : Window { History:
It was a child of Window before, but as of September 29, 2024, it is now a child of `Dialog`.
+/
class MessageBox : Dialog {
private string message; private string message;
MessageBoxButton buttonPressed = MessageBoxButton.None; MessageBoxButton buttonPressed = MessageBoxButton.None;
/// /++
History:
The overload that takes `Window originator` was added on September 29, 2024.
+/
this(string message, string[] buttons = ["OK"], MessageBoxButton[] buttonIds = [MessageBoxButton.OK]) { this(string message, string[] buttons = ["OK"], MessageBoxButton[] buttonIds = [MessageBoxButton.OK]) {
super(300, 100); this(null, message, buttons, buttonIds);
}
/// ditto
this(Window originator, string message, string[] buttons = ["OK"], MessageBoxButton[] buttonIds = [MessageBoxButton.OK]) {
message = message.stripRightInternal;
int mainWidth;
// estimate longest line
int count;
foreach(ch; message) {
if(ch == '\n') {
if(count > mainWidth)
mainWidth = count;
count = 0;
} else {
count++;
}
}
mainWidth *= 8;
if(mainWidth < 300)
mainWidth = 300;
if(mainWidth > 600)
mainWidth = 600;
super(originator, mainWidth, 100);
assert(buttons.length); assert(buttons.length);
assert(buttons.length == buttonIds.length); assert(buttons.length == buttonIds.length);
@ -13770,12 +13840,21 @@ class MessageBox : Window {
if(buttons.length == 1) if(buttons.length == 1)
auto spacer2 = new HorizontalSpacer(hl); // to center it auto spacer2 = new HorizontalSpacer(hl); // to center it
win.resize(scaleWithDpi(300), this.minHeight()); auto size = label.flexBasisHeight() + hl.minHeight() + this.paddingTop + this.paddingBottom;
auto max = scaleWithDpi(600); // random max height
if(size > max)
size = max;
win.resize(scaleWithDpi(mainWidth), size);
win.show(); win.show();
redraw(); redraw();
} }
override void OK() {
this.win.close();
}
mixin Padding!q{16}; mixin Padding!q{16};
} }
@ -13815,6 +13894,18 @@ enum MessageBoxButton {
Returns: the button pressed. Returns: the button pressed.
+/ +/
MessageBoxButton messageBox(string title, string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) { MessageBoxButton messageBox(string title, string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
return messageBox(null, title, message, style, icon);
}
/// ditto
int messageBox(string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
return messageBox(null, null, message, style, icon);
}
/++
+/
MessageBoxButton messageBox(Window originator, string title, string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
version(win32_widgets) { version(win32_widgets) {
WCharzBuffer t = WCharzBuffer(title); WCharzBuffer t = WCharzBuffer(title);
WCharzBuffer m = WCharzBuffer(message); WCharzBuffer m = WCharzBuffer(message);
@ -13835,7 +13926,7 @@ MessageBoxButton messageBox(string title, string message, MessageBoxStyle style
case Warning: type |= MB_ICONWARNING; break; case Warning: type |= MB_ICONWARNING; break;
case Error: type |= MB_ICONERROR; break; case Error: type |= MB_ICONERROR; break;
} }
switch(MessageBoxW(null, m.ptr, t.ptr, type)) { switch(MessageBoxW(originator is null ? null : originator.win.hwnd, m.ptr, t.ptr, type)) {
case IDOK: return MessageBoxButton.OK; case IDOK: return MessageBoxButton.OK;
case IDCANCEL: return MessageBoxButton.Cancel; case IDCANCEL: return MessageBoxButton.Cancel;
case IDTRYAGAIN, IDRETRY: return MessageBoxButton.Retry; case IDTRYAGAIN, IDRETRY: return MessageBoxButton.Retry;
@ -13874,20 +13965,20 @@ MessageBoxButton messageBox(string title, string message, MessageBoxStyle style
buttonIds = [MessageBoxButton.Retry, MessageBoxButton.Cancel, MessageBoxButton.Continue]; buttonIds = [MessageBoxButton.Retry, MessageBoxButton.Cancel, MessageBoxButton.Continue];
break; break;
} }
auto mb = new MessageBox(message, buttons, buttonIds); auto mb = new MessageBox(originator, message, buttons, buttonIds);
EventLoop el = EventLoop.get; EventLoop el = EventLoop.get;
el.run(() { return !mb.win.closed; }); el.run(() { return !mb.win.closed; });
return mb.buttonPressed; return mb.buttonPressed;
} }
} }
/// ditto /// ditto
int messageBox(string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) { int messageBox(Window originator, string message, MessageBoxStyle style = MessageBoxStyle.OK, MessageBoxIcon icon = MessageBoxIcon.None) {
return messageBox(null, message, style, icon); return messageBox(originator, message, style, icon);
} }
/// ///
alias void delegate(Widget handlerAttachedTo, Event event) EventHandler; alias void delegate(Widget handlerAttachedTo, Event event) EventHandler;
@ -15281,10 +15372,39 @@ struct FileName(alias storage = previousFileReferenced, string[] filters = null,
a directory picker in addition to the command line completion view. a directory picker in addition to the command line completion view.
The `initialDirectory` argument was added November 9, 2022 (dub v10.10) The `initialDirectory` argument was added November 9, 2022 (dub v10.10)
The `owner` argument was added September 29, 2024. The overloads without this argument are likely to be deprecated in the next major version.
Future_directions: Future_directions:
I want to add some kind of custom preview and maybe thumbnail thing in the future, I want to add some kind of custom preview and maybe thumbnail thing in the future,
at least on Linux, maybe on Windows too. at least on Linux, maybe on Windows too.
+/ +/
void getOpenFileName(
Window owner,
void delegate(string) onOK,
string prefilledName = null,
string[] filters = null,
void delegate() onCancel = null,
string initialDirectory = null,
)
{
return getFileName(owner, true, onOK, prefilledName, filters, onCancel, initialDirectory);
}
/// ditto
void getSaveFileName(
Window owner,
void delegate(string) onOK,
string prefilledName = null,
string[] filters = null,
void delegate() onCancel = null,
string initialDirectory = null,
)
{
return getFileName(owner, false, onOK, prefilledName, filters, onCancel, initialDirectory);
}
// deprecated("Pass an explicit owner window as the first argument, even if `null`. You can usually pass the `parentWindow` member of the widget that prompted this interaction.")
/// ditto
void getOpenFileName( void getOpenFileName(
void delegate(string) onOK, void delegate(string) onOK,
string prefilledName = null, string prefilledName = null,
@ -15293,7 +15413,7 @@ void getOpenFileName(
string initialDirectory = null, string initialDirectory = null,
) )
{ {
return getFileName(true, onOK, prefilledName, filters, onCancel, initialDirectory); return getFileName(null, true, onOK, prefilledName, filters, onCancel, initialDirectory);
} }
/// ditto /// ditto
@ -15305,10 +15425,11 @@ void getSaveFileName(
string initialDirectory = null, string initialDirectory = null,
) )
{ {
return getFileName(false, onOK, prefilledName, filters, onCancel, initialDirectory); return getFileName(null, false, onOK, prefilledName, filters, onCancel, initialDirectory);
} }
void getFileName( void getFileName(
Window owner,
bool openOrSave, bool openOrSave,
void delegate(string) onOK, void delegate(string) onOK,
string prefilledName = null, string prefilledName = null,
@ -15339,6 +15460,7 @@ void getFileName(
makeWindowsString(prefilledName, file[]); makeWindowsString(prefilledName, file[]);
OPENFILENAME ofn; OPENFILENAME ofn;
ofn.lStructSize = ofn.sizeof; ofn.lStructSize = ofn.sizeof;
ofn.hwndOwner = owner is null ? null : owner.win.hwnd;
if(filters.length) { if(filters.length) {
string filter; string filter;
foreach(i, f; filters) { foreach(i, f; filters) {
@ -15370,7 +15492,7 @@ void getFileName(
} else version(custom_widgets) { } else version(custom_widgets) {
if(filters.length == 0) if(filters.length == 0)
filters = ["All Files\0*.*"]; filters = ["All Files\0*.*"];
auto picker = new FilePicker(prefilledName, filters, initialDirectory); auto picker = new FilePicker(prefilledName, filters, initialDirectory, owner);
picker.onOK = onOK; picker.onOK = onOK;
picker.onCancel = onCancel; picker.onCancel = onCancel;
picker.show(); picker.show();
@ -15426,6 +15548,8 @@ class FilePicker : Dialog {
}); });
extern(C) static int comparator(scope const void* a, scope const void* b) { extern(C) static int comparator(scope const void* a, scope const void* b) {
// FIXME: make it a natural sort for numbers
// maybe put dot files at the end too.
auto sa = *cast(string*) a; auto sa = *cast(string*) a;
auto sb = *cast(string*) b; auto sb = *cast(string*) b;
@ -15461,7 +15585,7 @@ class FilePicker : Dialog {
//string[] filters = null, // format here is like ["Text files\0*.txt;*.text", "Image files\n*.png;*.jpg"] //string[] filters = null, // format here is like ["Text files\0*.txt;*.text", "Image files\n*.png;*.jpg"]
this(string prefilledName, string[] filters, string initialDirectory, Window owner = null) { this(string prefilledName, string[] filters, string initialDirectory, Window owner = null) {
super(300, 200, "Choose File..."); // owner); super(owner, 500, 400, "Choose File..."); // owner);
foreach(filter; filters) { foreach(filter; filters) {
while(filter.length && filter[0] != 0) { while(filter.length && filter[0] != 0) {
@ -15718,7 +15842,7 @@ class ObjectInspectionWindowImpl(T) : ObjectInspectionWindow {
Creates a dialog based on a data structure. Creates a dialog based on a data structure.
--- ---
dialog((YourStructure value) { dialog(window, (YourStructure value) {
// the user filled in the struct and clicked OK, // the user filled in the struct and clicked OK,
// you can check the members now // you can check the members now
}); });
@ -15730,14 +15854,29 @@ class ObjectInspectionWindowImpl(T) : ObjectInspectionWindow {
History: History:
The overload that lets you specify `initialData` was added on December 30, 2021 (dub v10.5) The overload that lets you specify `initialData` was added on December 30, 2021 (dub v10.5)
The overloads with `parent` were added September 29, 2024. The ones without it are likely to
be deprecated soon.
+/ +/
/// Group: generating_from_code /// Group: generating_from_code
void dialog(T)(void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) { void dialog(T)(void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) {
dialog(T.init, onOK, onCancel, title); dialog(null, T.init, onOK, onCancel, title);
} }
/// ditto /// ditto
void dialog(T)(T initialData, void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) { void dialog(T)(T initialData, void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) {
auto dg = new AutomaticDialog!T(initialData, onOK, onCancel, title); dialog(null, T.init, onOK, onCancel, title);
}
/// ditto
void dialog(T)(Window parent, void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) {
dialog(parent, T.init, onOK, onCancel, title);
}
/// ditto
void dialog(T)(T initialData, Window parent, void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) {
dialog(parent, initialData, onOK, onCancel, title);
}
/// ditto
void dialog(T)(Window parent, T initialData, void delegate(T) onOK, void delegate() onCancel = null, string title = T.stringof) {
auto dg = new AutomaticDialog!T(parent, initialData, onOK, onCancel, title);
dg.show(); dg.show();
} }
@ -15800,7 +15939,7 @@ class AutomaticDialog(T) : Dialog {
override int paddingRight() { return defaultLineHeight; } override int paddingRight() { return defaultLineHeight; }
override int paddingLeft() { return defaultLineHeight; } override int paddingLeft() { return defaultLineHeight; }
this(T initialData, void delegate(T) onOK, void delegate() onCancel, string title) { this(Window parent, T initialData, void delegate(T) onOK, void delegate() onCancel, string title) {
assert(onOK !is null); assert(onOK !is null);
t = initialData; t = initialData;
@ -15811,7 +15950,7 @@ class AutomaticDialog(T) : Dialog {
} }
this.onOK = onOK; this.onOK = onOK;
this.onCancel = onCancel; this.onCancel = onCancel;
super(400, cast(int)(__traits(allMembers, T).length * 2) * (defaultLineHeight + scaleWithDpi(4 + 2)) + defaultLineHeight + scaleWithDpi(56), title); super(parent, 400, cast(int)(__traits(allMembers, T).length * 2) * (defaultLineHeight + scaleWithDpi(4 + 2)) + defaultLineHeight + scaleWithDpi(56), title);
static if(is(T == class)) static if(is(T == class))
this.addDataControllerWidget(t); this.addDataControllerWidget(t);

View file

@ -59,7 +59,7 @@ class ColorPickerDialog : Dialog {
void delegate(Color) onOK; void delegate(Color) onOK;
this(Color current, void delegate(Color) onOK, Window owner) { this(Color current, void delegate(Color) onOK, Window owner) {
super(360, 460, "Color picker"); super(owner, 360, 460, "Color picker");
this.onOK = onOK; this.onOK = onOK;

View file

@ -1583,9 +1583,10 @@ enum WindowTypes : int {
splashScreen, /// a loading splash screen for your application splashScreen, /// a loading splash screen for your application
tooltip, /// A tiny window showing temporary help text or something. tooltip, /// A tiny window showing temporary help text or something.
comboBoxDropdown, comboBoxDropdown,
dialog,
toolbar toolbar
*/ */
/// a dialog box of some sort
dialog,
/// a child nested inside the parent. You must pass a parent window to the ctor /// a child nested inside the parent. You must pass a parent window to the ctor
nestedChild, nestedChild,
@ -2096,9 +2097,8 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
} }
version(X11) version(X11)
if(useFallbackDpi) if(useFallbackDpi || actualDpi_ == 0) // FIXME: the actualDpi_ will be populated eventually when we get the first synthetic configure event from the window manager, but that might be a little while so actualDpi_ can be 0 until then...
actualDpi_ = cast(int) (getDpi()[0] * customScalingFactorForMonitor(0)); actualDpi_ = cast(int) (getDpi()[0] * customScalingFactorForMonitor(0));
return actualDpi_; return actualDpi_;
} }
@ -2485,7 +2485,7 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
case normal, undecorated, eventOnly: case normal, undecorated, eventOnly:
case nestedChild, minimallyWrapped: case nestedChild, minimallyWrapped:
return (customizationFlags & WindowFlags.transient) ? true : false; return (customizationFlags & WindowFlags.transient) ? true : false;
case dropdownMenu, popupMenu, notification: case dropdownMenu, popupMenu, notification, dialog:
return true; return true;
} }
} }
@ -12270,6 +12270,9 @@ version(Windows) {
style = WS_POPUP; style = WS_POPUP;
flags |= WS_EX_NOACTIVATE; flags |= WS_EX_NOACTIVATE;
break; break;
case WindowTypes.dialog:
style = WS_OVERLAPPEDWINDOW;
break;
case WindowTypes.nestedChild: case WindowTypes.nestedChild:
style = WS_CHILD; style = WS_CHILD;
break; break;
@ -15451,6 +15454,10 @@ mixin DynamicLoad!(XRandr, "Xrandr", 2, XRandrLibrarySuccessfullyLoaded) XRandrL
break; break;
case WindowTypes.minimallyWrapped: case WindowTypes.minimallyWrapped:
assert(0, "don't create a minimallyWrapped thing explicitly!"); assert(0, "don't create a minimallyWrapped thing explicitly!");
case WindowTypes.dialog:
setNetWMWindowType(GetAtom!"_NET_WM_WINDOW_TYPE_DIALOG"(display));
break;
/+ /+
case WindowTypes.menu: case WindowTypes.menu:
atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_MENU"(display); atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_MENU"(display);
@ -15474,9 +15481,6 @@ mixin DynamicLoad!(XRandr, "Xrandr", 2, XRandrLibrarySuccessfullyLoaded) XRandrL
case WindowTypes.splash: case WindowTypes.splash:
atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_SPLASH"(display); atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_SPLASH"(display);
break; break;
case WindowTypes.dialog:
atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_DIALOG"(display);
break;
case WindowTypes.tooltip: case WindowTypes.tooltip:
atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_TOOLTIP"(display); atoms[0] = GetAtom!"_NET_WM_WINDOW_TYPE_TOOLTIP"(display);
break; break;
@ -15530,6 +15534,7 @@ mixin DynamicLoad!(XRandr, "Xrandr", 2, XRandrLibrarySuccessfullyLoaded) XRandrL
if(isTransient && parent) { // customizationFlags & WindowFlags.transient) { if(isTransient && parent) { // customizationFlags & WindowFlags.transient) {
if(parent is null) assert(0); if(parent is null) assert(0);
// sdpyPrintDebugString("transient");
XChangeProperty( XChangeProperty(
display, display,
impl.window, impl.window,

View file

@ -2340,10 +2340,17 @@ class TextLayouter {
} }
} }
finishLine(text.length, font); auto finished = finishLine(text.length, font);
/+
if(!finished)
currentCorner.y += lineHeight;
import arsd.core; writeln(finished);
+/
_height = currentCorner.y; _height = currentCorner.y;
// import arsd.core;writeln(_height);
assert(segments.length); assert(segments.length);
//return widths; //return widths;