diff options
| -rw-r--r-- | plugingui/drumkitframecontent.cc | 14 | ||||
| -rw-r--r-- | plugingui/nativewindow.h | 11 | ||||
| -rw-r--r-- | plugingui/nativewindow_cocoa.h | 2 | ||||
| -rw-r--r-- | plugingui/nativewindow_cocoa.mm | 39 | ||||
| -rw-r--r-- | plugingui/nativewindow_win32.cc | 23 | ||||
| -rw-r--r-- | plugingui/nativewindow_win32.h | 3 | ||||
| -rw-r--r-- | plugingui/nativewindow_x11.cc | 84 | ||||
| -rw-r--r-- | plugingui/nativewindow_x11.h | 2 | ||||
| -rw-r--r-- | plugingui/widget.cc | 5 | ||||
| -rw-r--r-- | plugingui/widget.h | 14 | ||||
| -rw-r--r-- | plugingui/window.cc | 16 | ||||
| -rw-r--r-- | plugingui/window.h | 6 | 
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; | 
