summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2019-10-09 18:02:19 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2019-10-09 18:02:19 +0200
commit2d6cbf8a0bb81bfe55a7d4e04d53a704f93c6b2e (patch)
tree80bab0705a6d5aec8569a3ed626a33a6224cf4f0
parent9b7299412d10e68c8aacc5f0debb7c80bf874120 (diff)
Make FileBrowser window always-on-top and try to position it inside the plugin gui window rectangle.
-rw-r--r--plugingui/drumkitframecontent.cc14
-rw-r--r--plugingui/nativewindow.h11
-rw-r--r--plugingui/nativewindow_cocoa.h2
-rw-r--r--plugingui/nativewindow_cocoa.mm39
-rw-r--r--plugingui/nativewindow_win32.cc23
-rw-r--r--plugingui/nativewindow_win32.h3
-rw-r--r--plugingui/nativewindow_x11.cc84
-rw-r--r--plugingui/nativewindow_x11.h2
-rw-r--r--plugingui/widget.cc5
-rw-r--r--plugingui/widget.h14
-rw-r--r--plugingui/window.cc16
-rw-r--r--plugingui/window.h6
12 files changed, 210 insertions, 9 deletions
diff --git a/plugingui/drumkitframecontent.cc b/plugingui/drumkitframecontent.cc
index 1da7201..0850ac1 100644
--- a/plugingui/drumkitframecontent.cc
+++ b/plugingui/drumkitframecontent.cc
@@ -168,6 +168,13 @@ void DrumkitframeContent::kitBrowseClick()
CONNECT(&file_browser, fileSelectNotifier,
this, &DrumkitframeContent::selectKitFile);
file_browser.show();
+ Point p{ window()->x() + (int)window()->width() / 2,
+ window()->y() + (int)window()->height() / 2 };
+ auto p0 = window()->translateToScreen(p);
+ auto sz = file_browser.window()->getNativeSize();
+ file_browser.move(p0.x - sz.width / 2,
+ p0.y - sz.height / 2);
+ file_browser.setAlwaysOnTop(true);
}
void DrumkitframeContent::midimapBrowseClick()
@@ -189,6 +196,13 @@ void DrumkitframeContent::midimapBrowseClick()
CONNECT(&file_browser, fileSelectNotifier,
this, &DrumkitframeContent::selectMapFile);
file_browser.show();
+ Point p{ window()->x() + (int)window()->width() / 2,
+ window()->y() + (int)window()->height() / 2 };
+ auto p0 = window()->translateToScreen(p);
+ auto sz = file_browser.window()->getNativeSize();
+ file_browser.move(p0.x - sz.width / 2,
+ p0.y - sz.height / 2);
+ file_browser.setAlwaysOnTop(true);
}
void DrumkitframeContent::defaultPathChanged(const std::string& path)
diff --git a/plugingui/nativewindow.h b/plugingui/nativewindow.h
index 3995d43..400ff57 100644
--- a/plugingui/nativewindow.h
+++ b/plugingui/nativewindow.h
@@ -37,6 +37,8 @@
namespace GUI
{
+struct Point;
+
//! Interface class for native window implementations.
class NativeWindow
{
@@ -48,6 +50,9 @@ public:
//! It resizes the window and disallows user resizing.
virtual void setFixedSize(std::size_t width, std::size_t height) = 0;
+ //! Force window to stay on top of other windows
+ virtual void setAlwaysOnTop(bool always_on_top) = 0;
+
//! Set a new size of the window.
virtual void resize(std::size_t width, std::size_t height) = 0;
@@ -84,8 +89,12 @@ public:
//! \return A queue of shared pointers to events.
virtual EventQueue getEvents() = 0;
- // \returns the native window handle, it HWND on Win32 or Window id on X11
+ //! \returns the native window handle, it HWND on Win32 or Window id on X11
virtual void* getNativeWindowHandle() const = 0;
+
+ //! Translate a the local native window coordinate to a global screen
+ //! coordinate.
+ virtual Point translateToScreen(const Point& point) = 0;
};
} // GUI::
diff --git a/plugingui/nativewindow_cocoa.h b/plugingui/nativewindow_cocoa.h
index 3f0518a..74eb2f4 100644
--- a/plugingui/nativewindow_cocoa.h
+++ b/plugingui/nativewindow_cocoa.h
@@ -43,6 +43,7 @@ public:
// From NativeWindow:
virtual void setFixedSize(std::size_t width, std::size_t height) override;
+ virtual void setAlwaysOnTop(bool always_on_top) override;
virtual void resize(std::size_t width, std::size_t height) override;
virtual std::pair<std::size_t, std::size_t> getSize() const override;
virtual void move(int x, int y) override;
@@ -55,6 +56,7 @@ public:
virtual void grabMouse(bool grab) override;
virtual EventQueue getEvents() override;
virtual void* getNativeWindowHandle() const override;
+ virtual Point translateToScreen(const Point& point) override;
// Expose friend members of Window to ObjC++ implementation.
class Window& getWindow();
diff --git a/plugingui/nativewindow_cocoa.mm b/plugingui/nativewindow_cocoa.mm
index aaacd0e..d8e889a 100644
--- a/plugingui/nativewindow_cocoa.mm
+++ b/plugingui/nativewindow_cocoa.mm
@@ -576,6 +576,18 @@ void NativeWindowCocoa::setFixedSize(std::size_t width, std::size_t height)
[priv->window setMaxSize:NSMakeSize(width, height + 22)];
}
+void NativeWindowCocoa::setAlwaysOnTop(bool always_on_top)
+{
+ if(always_on_top)
+ {
+ [priv->window setLevel: NSStatusWindowLevel];
+ }
+ else
+ {
+ [priv->window setLevel: NSNormalWindowLevel];
+ }
+}
+
void NativeWindowCocoa::resize(std::size_t width, std::size_t height)
{
[priv->window setContentSize:NSMakeSize(width, height)];
@@ -597,13 +609,15 @@ std::pair<std::size_t, std::size_t> NativeWindowCocoa::getSize() const
void NativeWindowCocoa::move(int x, int y)
{
- [priv->window setFrameTopLeftPoint:NSMakePoint(x, y)];
+ NSRect screen = [[NSScreen mainScreen] frame];
+ [priv->window setFrameTopLeftPoint:NSMakePoint(x, screen.size.height - y)];
}
std::pair<int, int> NativeWindowCocoa::getPosition() const
{
+ NSRect screen = [[NSScreen mainScreen] frame];
NSPoint pos = [[priv->window contentView] frame].origin;
- return {pos.x, pos.y};
+ return {pos.x, screen.size.height - pos.y};
}
void NativeWindowCocoa::show()
@@ -757,6 +771,27 @@ void* NativeWindowCocoa::getNativeWindowHandle() const
}
}
+Point NativeWindowCocoa::translateToScreen(const Point& point)
+{
+ NSRect e = [[NSScreen mainScreen] frame];
+ NSRect frame;
+ if(native_window)
+ {
+ frame = [priv->parent_view frame];
+ }
+ else
+ {
+ frame = [priv->view frame];
+ }
+
+ NSRect rect { { point.x + frame.origin.x,
+ frame.size.height - point.y + frame.origin.y},
+ {0.0, 0.0} };
+ rect = [priv->window convertRectToScreen:rect];
+
+ return { (int)rect.origin.x, (int)(e.size.height - rect.origin.y) };
+}
+
Window& NativeWindowCocoa::getWindow()
{
return window;
diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc
index 55f7c69..4b31130 100644
--- a/plugingui/nativewindow_win32.cc
+++ b/plugingui/nativewindow_win32.cc
@@ -452,6 +452,13 @@ void NativeWindowWin32::setFixedSize(std::size_t width, std::size_t height)
SetWindowLong(m_hwnd, GWL_STYLE, style);
}
+void NativeWindowWin32::setAlwaysOnTop(bool always_on_top)
+{
+ this->always_on_top = always_on_top;
+ SetWindowPos(m_hwnd, always_on_top ? HWND_TOPMOST : nullptr,
+ 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
void NativeWindowWin32::resize(std::size_t width, std::size_t height)
{
auto hwnd = m_hwnd;
@@ -461,7 +468,8 @@ void NativeWindowWin32::resize(std::size_t width, std::size_t height)
//}
// Set requested size on the window (or parent)
- SetWindowPos(hwnd, nullptr, -1, -1, (int)width, (int)height, SWP_NOMOVE);
+ SetWindowPos(hwnd, always_on_top ? HWND_TOPMOST : nullptr,
+ -1, -1, (int)width, (int)height, SWP_NOMOVE);
// Ask the client window what size it actually got
RECT rect;
@@ -470,7 +478,8 @@ void NativeWindowWin32::resize(std::size_t width, std::size_t height)
int h = height - rect.bottom;
// Set the compensated size on the window (or parent)
- SetWindowPos(hwnd, nullptr, -1, -1, width + w, height + h, SWP_NOMOVE);
+ SetWindowPos(hwnd, always_on_top ? HWND_TOPMOST : nullptr,
+ -1, -1, width + w, height + h, SWP_NOMOVE);
}
std::pair<std::size_t, std::size_t> NativeWindowWin32::getSize() const
@@ -482,7 +491,8 @@ std::pair<std::size_t, std::size_t> NativeWindowWin32::getSize() const
void NativeWindowWin32::move(int x, int y)
{
- SetWindowPos(m_hwnd, nullptr, (int)x, (int)y, -1, -1, SWP_NOSIZE);
+ SetWindowPos(m_hwnd, always_on_top ? HWND_TOPMOST : nullptr,
+ (int)x, (int)y, -1, -1, SWP_NOSIZE);
}
std::pair<int, int> NativeWindowWin32::getPosition() const
@@ -564,4 +574,11 @@ void* NativeWindowWin32::getNativeWindowHandle() const
return (void*)m_hwnd;
}
+Point NativeWindowWin32::translateToScreen(const Point& point)
+{
+ POINT p{ point.x, point.y };
+ ClientToScreen(m_hwnd, &p);
+ return { p.x, p.y };
+}
+
} // GUI::
diff --git a/plugingui/nativewindow_win32.h b/plugingui/nativewindow_win32.h
index d547dc0..046b38a 100644
--- a/plugingui/nativewindow_win32.h
+++ b/plugingui/nativewindow_win32.h
@@ -45,6 +45,7 @@ public:
~NativeWindowWin32();
void setFixedSize(std::size_t width, std::size_t height) override;
+ void setAlwaysOnTop(bool always_on_top) override;
void resize(std::size_t width, std::size_t height) override;
std::pair<std::size_t, std::size_t> getSize() const override;
void move(int x, int y) override;
@@ -57,6 +58,7 @@ public:
void grabMouse(bool grab) override;
EventQueue getEvents() override;
void* getNativeWindowHandle() const override;
+ Point translateToScreen(const Point& point) override;
private:
static LRESULT CALLBACK dialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
@@ -70,6 +72,7 @@ private:
std::pair<int, int> last_mouse_position{0, 0};
char* m_className = nullptr;
EventQueue event_queue;
+ bool always_on_top{false};
};
} // GUI::
diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc
index e96f26a..de215c2 100644
--- a/plugingui/nativewindow_x11.cc
+++ b/plugingui/nativewindow_x11.cc
@@ -44,6 +44,72 @@
namespace GUI
{
+#define _NET_WM_STATE_REMOVE 0 // remove/unset property
+#define _NET_WM_STATE_ADD 1 // add/set property
+
+void setWindowFront(Display *disp, ::Window wind, bool enable)
+{
+ Atom wm_state, wm_state_above;
+ XEvent event;
+
+ if((wm_state = XInternAtom(disp, "_NET_WM_STATE", False)) == None)
+ {
+ return;
+ }
+
+ if((wm_state_above = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False)) == None)
+ {
+ return;
+ }
+ //
+ //window = the respective client window
+ //message_type = _NET_WM_STATE
+ //format = 32
+ //data.l[0] = the action, as listed below
+ //data.l[1] = first property to alter
+ //data.l[2] = second property to alter
+ //data.l[3] = source indication (0-unk,1-normal app,2-pager)
+ //other data.l[] elements = 0
+ //
+
+ // sending a ClientMessage
+ event.xclient.type = ClientMessage;
+
+ // value unimportant in this case
+ event.xclient.serial = 0;
+
+ // coming from a SendEvent request, so True
+ event.xclient.send_event = True;
+
+ // the event originates from disp
+ event.xclient.display = disp;
+
+ // the window whose state will be modified
+ event.xclient.window = wind;
+
+ // the component Atom being modified in the window
+ event.xclient.message_type = wm_state;
+
+ // specifies that data.l will be used
+ event.xclient.format = 32;
+
+ // 0 is _NET_WM_STATE_REMOVE, 1 is _NET_WM_STATE_ADD
+ event.xclient.data.l[0] =
+ enable ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+
+ // the atom being added
+ event.xclient.data.l[1] = wm_state_above;
+
+ // unused
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ // actually send the event
+ XSendEvent(disp, DefaultRootWindow(disp), False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &event);
+}
+
NativeWindowX11::NativeWindowX11(void* native_window, Window& window)
: window(window)
{
@@ -101,8 +167,8 @@ NativeWindowX11::NativeWindowX11(void* native_window, Window& window)
wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", false);
Atom protocols[] = { wmDeleteMessage };
- int count = sizeof(protocols)/sizeof(Atom);
- XSetWMProtocols(display, xwindow, protocols, count);
+ XSetWMProtocols(display, xwindow, protocols,
+ sizeof(protocols) / sizeof(*protocols));
// Create a "Graphics Context"
gc = XCreateGC(display, xwindow, 0, nullptr);
@@ -142,6 +208,11 @@ void NativeWindowX11::setFixedSize(std::size_t width, std::size_t height)
XSetNormalHints(display, xwindow, &size_hints);
}
+void NativeWindowX11::setAlwaysOnTop(bool always_on_top)
+{
+ setWindowFront(display, xwindow, always_on_top);
+}
+
void NativeWindowX11::resize(std::size_t width, std::size_t height)
{
if(display == nullptr)
@@ -287,6 +358,15 @@ void* NativeWindowX11::getNativeWindowHandle() const
return (void*)xwindow;
}
+Point NativeWindowX11::translateToScreen(const Point& point)
+{
+ ::Window child_window;
+ Point p;
+ XTranslateCoordinates(display, xwindow, DefaultRootWindow(display),
+ point.x, point.y, &p.x, &p.y, &child_window);
+ return p;
+}
+
void NativeWindowX11::translateXMessage(XEvent& xevent)
{
switch(xevent.type)
diff --git a/plugingui/nativewindow_x11.h b/plugingui/nativewindow_x11.h
index eb88b6c..cb56fbc 100644
--- a/plugingui/nativewindow_x11.h
+++ b/plugingui/nativewindow_x11.h
@@ -47,6 +47,7 @@ public:
// From NativeWindow:
void setFixedSize(std::size_t width, std::size_t height) override;
+ void setAlwaysOnTop(bool always_on_top) override;
void resize(std::size_t width, std::size_t height) override;
std::pair<std::size_t, std::size_t> getSize() const override;
void move(int x, int y) override;
@@ -59,6 +60,7 @@ public:
void grabMouse(bool grab) override;
EventQueue getEvents() override;
void* getNativeWindowHandle() const override;
+ Point translateToScreen(const Point& point) override;
private:
void translateXMessage(XEvent& xevent);
diff --git a/plugingui/widget.cc b/plugingui/widget.cc
index c148219..5a76af9 100644
--- a/plugingui/widget.cc
+++ b/plugingui/widget.cc
@@ -196,6 +196,11 @@ std::size_t Widget::height() const
return _height;
}
+Point Widget::position() const
+{
+ return { _x, _y };
+}
+
PixelBufferAlpha& Widget::GetPixelBuffer()
{
return pixbuf;
diff --git a/plugingui/widget.h b/plugingui/widget.h
index 8595ef7..fbf3f5b 100644
--- a/plugingui/widget.h
+++ b/plugingui/widget.h
@@ -37,6 +37,18 @@
namespace GUI
{
+struct Point
+{
+ int x;
+ int y;
+};
+
+struct Size
+{
+ std::size_t width;
+ std::size_t height;
+};
+
class ImageCache;
class Window;
@@ -66,6 +78,8 @@ public:
virtual std::size_t width() const override;
virtual std::size_t height() const override;
+ Point position() const;
+
// From Canvas
PixelBufferAlpha& GetPixelBuffer() override;
diff --git a/plugingui/window.cc b/plugingui/window.cc
index 60ecf02..a9deed5 100644
--- a/plugingui/window.cc
+++ b/plugingui/window.cc
@@ -86,6 +86,11 @@ void Window::setFixedSize(int w, int h)
native->setFixedSize(w, h);
}
+void Window::setAlwaysOnTop(bool always_on_top)
+{
+ native->setAlwaysOnTop(always_on_top);
+}
+
void Window::setCaption(const std::string& caption)
{
native->setCaption(caption);
@@ -125,6 +130,12 @@ Window* Window::window()
return this;
}
+Size Window::getNativeSize()
+{
+ auto sz = native->getSize();
+ return {sz.first, sz.second};
+}
+
ImageCache& Window::getImageCache()
{
return image_cache;
@@ -188,6 +199,11 @@ void* Window::getNativeWindowHandle() const
return native->getNativeWindowHandle();
}
+Point Window::translateToScreen(const Point& point)
+{
+ return native->translateToScreen(point);
+}
+
std::size_t Window::translateToWindowX()
{
return 0;
diff --git a/plugingui/window.h b/plugingui/window.h
index e5bc496..6031500 100644
--- a/plugingui/window.h
+++ b/plugingui/window.h
@@ -45,6 +45,7 @@ public:
~Window();
void setFixedSize(int width, int height);
+ void setAlwaysOnTop(bool always_on_top);
void setCaption(const std::string& caption);
// From Widget:
@@ -53,7 +54,7 @@ public:
void show() override;
void hide() override;
Window* window() override;
-
+ Size getNativeSize();
ImageCache& getImageCache() override;
EventHandler* eventHandler();
@@ -73,6 +74,9 @@ public:
// \returns the native window handle, it HWND on Win32 or Window id on X11
void* getNativeWindowHandle() const;
+ //! Translate a local window coordinate to a global screen coordinate.
+ Point translateToScreen(const Point& point);
+
protected:
// For the EventHandler
friend class EventHandler;