Merge branch 'master' of github.com:buggins/dlangui

This commit is contained in:
Vadim Lopatin 2017-10-09 09:33:21 +03:00
commit 132bfd8c2a
4 changed files with 117 additions and 89 deletions

View File

@ -266,7 +266,9 @@ extern (C) int UIAppMain(string[] args) {
//}
// create window
Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 800, 700);
//Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 800, 700);
// Expand window size if content is bigger than 800, 700 (change to above version if you want scrollbars and 800, 700 size)
Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable | WindowFlag.ExpandSize, 800, 700);
// here you can see window or content resize mode
//Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 400, 400);
//window.windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;

View File

@ -56,6 +56,8 @@ enum WindowFlag : uint {
MeasureSize = 8,
/// window without decorations
Borderless = 16,
/// expand window size if main widget minimal size is greater than size defined in window constructor
ExpandSize = 32,
}
/// Window states
@ -333,9 +335,9 @@ class Window : CustomEventTarget {
@property bool caretReplace() { return _caretReplace; }
// window content resize mode
protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;
//protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;
//protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.shrinkWidgets;
//protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.scrollWindow;
protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.scrollWindow;
@property WindowOrContentResizeMode windowOrContentResizeMode() {return _windowOrContentResizeMode; }
@property void windowOrContentResizeMode(WindowOrContentResizeMode newMode) {
@ -466,7 +468,7 @@ class Window : CustomEventTarget {
void adjustWindowOrContentSize(int minContentWidth, int minContentHeight) {
_minContentWidth = minContentWidth;
_minContentHeight = minContentHeight;
if (_windowOrContentResizeMode == WindowOrContentResizeMode.resizeWindow)
if (_windowOrContentResizeMode == WindowOrContentResizeMode.resizeWindow || flags & WindowFlag.ExpandSize)
resizeWindow(Point(max(_windowRect.right, minContentWidth), max(_windowRect.bottom, minContentHeight)));
updateWindowOrContentSize();
}

View File

@ -412,7 +412,19 @@ class SDLWindow : Window {
if (_windowState != WindowState.normal) {
SDL_RestoreWindow(_win);
version(linux) {
// some SDL versions, reset windows size and position to values from create window (SDL 2.0.4) on linux (don't know how it works on macOS)
// On linux with Cinnamon desktop, changing window state from for example minimized reset windows size
// and/or position to values from create window (last tested on Cinamon 3.4.6 with SDL 2.0.4)
//
// Steps to reproduce:
// Need app with two windows - dlangide for example.
// 1. Comment this fix
// 2. dub run --force
// 3. After first window appear move it and/or change window size
// 4. Click on button to open file
// 5. Click on window icon minimize in open file dialog
// 6. Restore window clicking on taskbar
// 7. The first main window has old position/size
// Xfce works OK without this fix
if (newWindowRect.bottom == int.min && newWindowRect.right == int.min)
SDL_SetWindowSize(_win, _windowRect.right, _windowRect.bottom);

View File

@ -101,6 +101,7 @@ private __gshared
Atom atom_DLANGUI_TASK_EVENT;
Atom atom_DLANGUI_CLOSE_WINDOW_EVENT;
Atom atom_DLANGUI_CLIPBOARD_BUFFER;
Atom atom_DLANGUI_REDRAW_EVENT;
}
static void setupX11Atoms()
@ -127,6 +128,7 @@ static void setupX11Atoms()
atom_DLANGUI_TASK_EVENT = XInternAtom(x11display, "DLANGUI_TASK_EVENT", False);
atom_DLANGUI_CLOSE_WINDOW_EVENT = XInternAtom(x11display, "DLANGUI_CLOSE_WINDOW_EVENT", False);
atom_DLANGUI_CLIPBOARD_BUFFER = XInternAtom(x11display, "DLANGUI_CLIPBOARD_BUFFER", False);
atom_DLANGUI_REDRAW_EVENT = XInternAtom(x11display, "DLANGUI_REDRAW_EVENT", False);
}
// Cursor font constants
@ -254,7 +256,6 @@ class X11Window : DWindow {
X11Window[] _children;
X11Window _parent;
bool _needRedraw;
int _cachedWidth, _cachedHeight;
static if (ENABLE_OPENGL) {
@ -440,11 +441,19 @@ class X11Window : DWindow {
}
}
private bool hasVisibleModalChild() {
foreach (X11Window w;_children) {
if (w.flags & WindowFlag.Modal && w._windowState != WindowState.hidden)
return true;
}
return false;
}
/// show window
override void show() {
Log.d("X11Window.show");
XMapRaised(x11display, _win);
XFlush(x11display);
static if (ENABLE_OPENGL) {
if (_enableOpengl) {
_glc = glXCreateContext(x11display, x11visual, null, GL_TRUE);
@ -476,6 +485,7 @@ class X11Window : DWindow {
_mainWidget.setFocus();
}
XFlush(x11display);
}
override protected void handleWindowStateChange(WindowState newState, Rect newWindowRect = RECT_VALUE_IS_NOT_SET) {
@ -652,12 +662,18 @@ class X11Window : DWindow {
XChangeProperty(x11display, _win, atom_NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, cast(ubyte*)propData.ptr, cast(int)propData.length);
}
uint _lastRedrawEventCode;
/// request window redraw
override void invalidate() {
if (!_needRedraw) {
debug(x11) Log.d("Window.invalidate()");
_needRedraw = true;
}
XEvent ev;
ev.xclient.type = ClientMessage;
ev.xclient.message_type = atom_DLANGUI_REDRAW_EVENT;
ev.xclient.window = _win;
ev.xclient.display = x11display;
ev.xclient.format = 32;
ev.xclient.data.l[0] = ++_lastRedrawEventCode;
XSendEvent(x11display, _win, false, StructureNotifyMask, &ev);
XFlush(x11display);
}
/// close window
@ -729,7 +745,7 @@ class X11Window : DWindow {
}
void redraw() {
_needRedraw = false;
_lastRedrawEventCode = 0;
//Use values cached by ConfigureNotify to avoid XGetWindowAttributes call.
//XWindowAttributes window_attributes_return;
//XGetWindowAttributes(x11display, _win, &window_attributes_return);
@ -749,14 +765,39 @@ class X11Window : DWindow {
protected ButtonDetails _mbutton;
protected ButtonDetails _rbutton;
ushort convertMouseFlags(uint flags) {
// x11 gives flags from time prior event so if left button is pressed there is not Button1Mask
ushort convertMouseFlags(uint flags, MouseButton btn, bool pressed) {
ushort res = 0;
if (flags & Button1Mask)
res |= MouseFlag.LButton;
if (flags & Button2Mask)
res |= MouseFlag.RButton;
if (flags & Button3Mask)
res |= MouseFlag.MButton;
if (btn == MouseButton.Left) {
if (pressed)
res |= MouseFlag.LButton;
else
res &= ~MouseFlag.LButton;
}
else
if (flags & Button1Mask)
res |= MouseFlag.LButton;
if (btn == MouseButton.Middle) {
if (pressed)
res |= MouseFlag.MButton;
else
res &= ~MouseFlag.MButton;
}
else
if (flags & Button2Mask)
res |= MouseFlag.MButton;
if (btn == MouseButton.Right) {
if (pressed)
res |= MouseFlag.RButton;
else
res &= ~MouseFlag.RButton;
}
else
if (flags & Button3Mask)
res |= MouseFlag.RButton;
return res;
}
@ -764,9 +805,9 @@ class X11Window : DWindow {
if (button == Button1)
return MouseButton.Left;
if (button == Button2)
return MouseButton.Right;
if (button == Button3)
return MouseButton.Middle;
if (button == Button3)
return MouseButton.Right;
return MouseButton.None;
}
@ -794,7 +835,9 @@ class X11Window : DWindow {
if (wheelDelta)
event = new MouseEvent(action, MouseButton.None, lastFlags, lastx, lasty, wheelDelta);
} else {
lastFlags = convertMouseFlags(state);
MouseButton btn = convertMouseButton(button);
lastFlags = convertMouseFlags(state, btn, action == MouseAction.ButtonDown);
if (_keyFlags & KeyFlag.Shift)
lastFlags |= MouseFlag.Shift;
if (_keyFlags & KeyFlag.Control)
@ -803,7 +846,6 @@ class X11Window : DWindow {
lastFlags |= MouseFlag.Alt;
lastx = cast(short)x;
lasty = cast(short)y;
MouseButton btn = convertMouseButton(button);
event = new MouseEvent(action, btn, lastFlags, lastx, lasty);
}
if (event) {
@ -824,6 +866,7 @@ class X11Window : DWindow {
event.lbutton = _lbutton;
event.rbutton = _rbutton;
event.mbutton = _mbutton;
bool res = dispatchMouseEvent(event);
if (res) {
debug(mouse) Log.d("Calling update() after mouse event");
@ -1237,7 +1280,6 @@ class X11Platform : Platform {
}
private X11Window[XWindow] _windowMap;
private X11Window[] _windowList;
/**
* create window
@ -1255,7 +1297,6 @@ class X11Platform : Platform {
int newheight = height;
X11Window window = new X11Window(this, windowCaption, parent, flags, newwidth, newheight);
_windowMap[window._win] = window;
_windowList ~= window;
return window;
}
@ -1284,17 +1325,6 @@ class X11Platform : Platform {
XSendEvent(x11display2, window._win, false, StructureNotifyMask, &ev);
XFlush(x11display2);
XUnlockDisplay(x11display2);
for (uint i = 0; i < _windowList.length; i++) {
if (w is _windowList[i]) {
for (uint j = i; j + 1 < _windowList.length; j++)
_windowList[j] = _windowList[j + 1];
_windowList[$ - 1] = null;
_windowList.length--;
break;
}
}
}
bool handleTimers() {
@ -1312,7 +1342,7 @@ class X11Platform : Platform {
return _windowMap.length == 0;
}
protected int numberOfPendingEvents()
protected int numberOfPendingEvents(int msecs = 10)
{
import core.sys.posix.sys.select;
int x11displayFd = ConnectionNumber(x11display);
@ -1326,13 +1356,14 @@ class X11Platform : Platform {
import core.stdc.errno;
int selectResult;
do {
timeval zeroTime;
selectResult = select(x11displayFd + 1, &fdSet, null, null, &zeroTime);
timeval timeout;
timeout.tv_usec = msecs;
selectResult = select(x11displayFd + 1, &fdSet, null, null, &timeout);
} while(selectResult == -1 && errno == EINTR);
if (selectResult < 0) {
Log.e("X11: display fd select error");
} else if (selectResult == 1) {
Log.d("X11: XPending");
//Log.d("X11: XPending");
eventsInQueue = XPending(x11display);
}
}
@ -1482,7 +1513,11 @@ class X11Platform : Platform {
Log.d("X11: ButtonPress event");
X11Window w = findWindow(event.xbutton.window);
if (w) {
w.processMouseEvent(MouseAction.ButtonDown, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
if (event.xbutton.button == 4 || event.xbutton.button == 5) {
w.processMouseEvent(MouseAction.Wheel, 0, 0, 0, event.xbutton.button == 4 ? 1 : -1);
} else {
w.processMouseEvent(MouseAction.ButtonDown, event.xbutton.button, event.xbutton.state, event.xbutton.x, event.xbutton.y);
}
} else {
Log.e("Window not found");
}
@ -1508,7 +1543,9 @@ class X11Platform : Platform {
case EnterNotify:
Log.d("X11: EnterNotify event");
X11Window w = findWindow(event.xcrossing.window);
if (!w) {
if (w) {
w.processMouseEvent(MouseAction.Move, 0, event.xmotion.state, event.xcrossing.x, event.xcrossing.y);
} else {
Log.e("Window not found");
}
break;
@ -1616,6 +1653,9 @@ class X11Platform : Platform {
w.handlePostedEvent(cast(uint)event.xclient.data.l[0]);
} else if (event.xclient.message_type == atom_DLANGUI_TIMER_EVENT) {
w.handleTimer();
} else if (event.xclient.message_type == atom_DLANGUI_REDRAW_EVENT) {
if (event.xclient.data.l[0] == w._lastRedrawEventCode)
w.redraw();
} else if (event.xclient.message_type == atom_WM_PROTOCOLS) {
Log.d("Handling WM_PROTOCOLS");
if ((event.xclient.format == 32) && (event.xclient.data.l[0]) == atom_WM_DELETE_WINDOW) {
@ -1636,41 +1676,30 @@ class X11Platform : Platform {
}
}
protected void pumpEvents()
{
XFlush(x11display);
// Note: only events we set the mask for are detected!
while(numberOfPendingEvents())
{
if (allWindowsClosed())
break;
XEvent event; /* the XEvent declaration !!! */
XNextEvent(x11display, &event);
processXEvent(event);
}
}
/**
* Starts application message loop.
*
* When returned from this method, application is shutting down.
*/
override int enterMessageLoop() {
import core.thread;
XEvent event; /* the XEvent declaration !!! */
KeySym key; /* a dealie-bob to handle KeyPress Events */
char[255] text; /* a char buffer for KeyPress Events */
Log.d("enterMessageLoop()");
while(!allWindowsClosed()) {
// Note: only events we set the mask for are detected!
foreach(win; _windowMap) {
if (win._needRedraw) {
win.redraw();
}
}
XFlush(x11display);
int eventsInQueue = numberOfPendingEvents();
if (!eventsInQueue) {
debug(x11) Log.d("X11: Sleeping");
Thread.sleep(dur!("msecs")(10));
}
foreach(eventIndex; 0..eventsInQueue)
{
if (allWindowsClosed())
break;
if (!numberOfPendingEvents())
break;
XNextEvent(x11display, &event);
processXEvent(event);
}
pumpEvents();
}
return 0;
}
@ -1710,18 +1739,7 @@ class X11Platform : Platform {
Log.e("Waiting for clipboard contents timeout");
return ""d;
}
XFlush(x11display);
int eventsInQueue = numberOfPendingEvents();
foreach(eventIndex; 0..eventsInQueue)
{
if (allWindowsClosed())
break;
if (!numberOfPendingEvents())
break;
XEvent event;
XNextEvent(x11display, &event);
processXEvent(event);
}
pumpEvents();
}
Atom selectionTarget;
int selectionFormat;
@ -1780,15 +1798,9 @@ class X11Platform : Platform {
/// returns true if there is some modal window opened above this window, and this window should not process mouse/key input and should not allow closing
override bool hasModalWindowsAbove(DWindow w) {
// override in platform specific class
for (uint i = 0; i + 1 < _windowList.length; i++) {
if (_windowList[i] is w) {
for (uint j = i + 1; j < _windowList.length; j++) {
if (_windowList[j].flags & WindowFlag.Modal && _windowList[j].windowState != WindowState.hidden)
return true;
}
return false;
}
X11Window x11Win = cast (X11Window) w;
if (x11Win) {
return x11Win.hasVisibleModalChild();
}
return false;
}