|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
/*
|
|
|
|
|
* Platform Implementation
|
|
|
|
|
* Nana C++ Library(http://www.nanapro.org)
|
|
|
|
|
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
|
|
|
|
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
|
|
|
|
*
|
|
|
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
|
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
|
|
|
@@ -129,6 +129,140 @@ namespace nana{
|
|
|
|
|
{
|
|
|
|
|
nana::detail::platform_spec & spec = nana::detail::platform_spec::instance();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct frame_extents
|
|
|
|
|
{
|
|
|
|
|
long left;
|
|
|
|
|
long right;
|
|
|
|
|
long top;
|
|
|
|
|
long bottom;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
frame_extents x11_frame_extents(Window wd)
|
|
|
|
|
{
|
|
|
|
|
frame_extents fm_extents;
|
|
|
|
|
Atom type;
|
|
|
|
|
int format;
|
|
|
|
|
unsigned long len, bytes_left = 0;
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
|
|
|
|
|
if(Success == ::XGetWindowProperty(restrict::spec.open_display(), wd,
|
|
|
|
|
restrict::spec.atombase().net_frame_extents, 0, 16, 0,
|
|
|
|
|
XA_CARDINAL, &type, &format,
|
|
|
|
|
&len, &bytes_left, &data))
|
|
|
|
|
{
|
|
|
|
|
if(type != None && len == 4)
|
|
|
|
|
{
|
|
|
|
|
fm_extents.left = ((long*)data)[0];
|
|
|
|
|
fm_extents.right = ((long*)data)[1];
|
|
|
|
|
fm_extents.top = ((long*)data)[2];
|
|
|
|
|
fm_extents.bottom = ((long*)data)[3];
|
|
|
|
|
}
|
|
|
|
|
::XFree(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fm_extents;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//The XMoveWindow and XMoveResizeWindow don't take effect if the specified window is
|
|
|
|
|
//unmapped, and the members x and y of XSetSizeHints is obsoluted. So the position that
|
|
|
|
|
//set to a unmapped windows should be kept and use the position when the window is mapped.
|
|
|
|
|
std::map<Window, ::nana::point> exposed_positions; //locked by platform_scope_guard
|
|
|
|
|
|
|
|
|
|
//Returns the parent window.
|
|
|
|
|
//It may return a decoration frame window if the requested window is a top level and WM is a
|
|
|
|
|
//reparenting window manager.
|
|
|
|
|
native_window_type x11_parent_window(native_window_type wd)
|
|
|
|
|
{
|
|
|
|
|
Window root;
|
|
|
|
|
Window parent;
|
|
|
|
|
Window * children;
|
|
|
|
|
unsigned size;
|
|
|
|
|
|
|
|
|
|
platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast<Window>(wd),
|
|
|
|
|
&root, &parent, &children, &size))
|
|
|
|
|
{
|
|
|
|
|
::XFree(children);
|
|
|
|
|
return reinterpret_cast<native_window_type>(parent);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Revise the position for moving window. Because the window is moved depending on
|
|
|
|
|
//implementation of Window Manager. A reparenting window may not be moved the origin to
|
|
|
|
|
//the specified location. it may be moved the left-top corner to the specified location.
|
|
|
|
|
void x11_revise_position(native_window_type wd, int &x, int& y)
|
|
|
|
|
{
|
|
|
|
|
auto const disp = restrict::spec.open_display();
|
|
|
|
|
auto const owner = reinterpret_cast<Window>(restrict::spec.get_owner(wd));
|
|
|
|
|
auto const root_wd = restrict::spec.root_window();
|
|
|
|
|
|
|
|
|
|
Window decoration_wd = 0;
|
|
|
|
|
if(owner)
|
|
|
|
|
{
|
|
|
|
|
Window child;
|
|
|
|
|
|
|
|
|
|
if(owner != root_wd)
|
|
|
|
|
{
|
|
|
|
|
::XTranslateCoordinates(disp, owner, root_wd,
|
|
|
|
|
x, y, &x, &y, &child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
decoration_wd = reinterpret_cast<Window>(x11_parent_window(wd));
|
|
|
|
|
if((decoration_wd == owner) || (decoration_wd == root_wd))
|
|
|
|
|
decoration_wd = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(decoration_wd)
|
|
|
|
|
{
|
|
|
|
|
auto fm_extents = x11_frame_extents(reinterpret_cast<Window>(wd));
|
|
|
|
|
|
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
|
|
|
|
|
|
|
|
|
x += attr.x - fm_extents.left;
|
|
|
|
|
y += attr.y - fm_extents.top;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_apply_exposed_position(native_window_type wd)
|
|
|
|
|
{
|
|
|
|
|
nana::detail::platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
auto i = exposed_positions.find(reinterpret_cast<Window>(wd));
|
|
|
|
|
if(i == exposed_positions.cend())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
native_interface::move_window(wd, i->second.x, i->second.y);
|
|
|
|
|
|
|
|
|
|
exposed_positions.erase(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace x11_wait
|
|
|
|
|
{
|
|
|
|
|
static Bool configure(Display *disp, XEvent *evt, char *arg)
|
|
|
|
|
{
|
|
|
|
|
return disp && evt && arg && (evt->type == ConfigureNotify) && (evt->xconfigure.window == *reinterpret_cast<Window*>(arg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool map(Display *disp, XEvent *evt, char *arg)
|
|
|
|
|
{
|
|
|
|
|
return disp && evt && arg && (evt->type == MapNotify) && (evt->xmap.window == *reinterpret_cast<Window*>(arg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Bool unmap(Display *disp, XEvent *evt, char *arg)
|
|
|
|
|
{
|
|
|
|
|
return disp && evt && arg && (evt->type == MapNotify) && (evt->xunmap.window == *reinterpret_cast<Window*>(arg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*))
|
|
|
|
|
{
|
|
|
|
|
XEvent dummy;
|
|
|
|
|
::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast<XPointer>(&wd));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//struct native_interface
|
|
|
|
|
@@ -196,13 +330,6 @@ namespace nana{
|
|
|
|
|
return rectangle{ primary_monitor_size() };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NANA_X11
|
|
|
|
|
//The XMoveWindow and XMoveResizeWindow don't take effect if the specified window is
|
|
|
|
|
//unmapped, and the members x and y of XSetSizeHints is obsoluted. So the position that
|
|
|
|
|
//set to a unmapped windows should be kept and use the position when the window is mapped.
|
|
|
|
|
std::map<Window, ::nana::point> exposed_positions; //locked by platform_scope_guard
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//platform-dependent
|
|
|
|
|
native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app)
|
|
|
|
|
{
|
|
|
|
|
@@ -267,7 +394,7 @@ namespace nana{
|
|
|
|
|
|
|
|
|
|
XSetWindowAttributes win_attr;
|
|
|
|
|
unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
|
|
|
|
|
CWWinGravity | CWBitGravity | CWColormap | CWEventMask;
|
|
|
|
|
CWColormap | CWEventMask;
|
|
|
|
|
|
|
|
|
|
Display * disp = restrict::spec.open_display();
|
|
|
|
|
win_attr.colormap = restrict::spec.colormap();
|
|
|
|
|
@@ -276,8 +403,6 @@ namespace nana{
|
|
|
|
|
win_attr.background_pixel = 0xFFFFFF;
|
|
|
|
|
win_attr.border_pixmap = None;
|
|
|
|
|
win_attr.border_pixel = 0x0;
|
|
|
|
|
win_attr.bit_gravity = 0;
|
|
|
|
|
win_attr.win_gravity = NorthWestGravity;
|
|
|
|
|
win_attr.backing_store = 0;
|
|
|
|
|
win_attr.backing_planes = 0;
|
|
|
|
|
win_attr.backing_pixel = 0;
|
|
|
|
|
@@ -424,7 +549,7 @@ namespace nana{
|
|
|
|
|
|
|
|
|
|
XSetWindowAttributes win_attr;
|
|
|
|
|
unsigned long attr_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
|
|
|
|
|
CWWinGravity | CWBitGravity | CWColormap | CWEventMask;
|
|
|
|
|
CWColormap | CWEventMask | CWOverrideRedirect;
|
|
|
|
|
|
|
|
|
|
Display * disp = restrict::spec.open_display();
|
|
|
|
|
win_attr.colormap = restrict::spec.colormap();
|
|
|
|
|
@@ -433,15 +558,12 @@ namespace nana{
|
|
|
|
|
win_attr.background_pixel = 0xFFFFFF;
|
|
|
|
|
win_attr.border_pixmap = None;
|
|
|
|
|
win_attr.border_pixel = 0x0;
|
|
|
|
|
win_attr.bit_gravity = 0;
|
|
|
|
|
win_attr.win_gravity = NorthWestGravity;
|
|
|
|
|
win_attr.backing_store = 0;
|
|
|
|
|
win_attr.backing_planes = 0;
|
|
|
|
|
win_attr.backing_pixel = 0;
|
|
|
|
|
win_attr.colormap = restrict::spec.colormap();
|
|
|
|
|
|
|
|
|
|
win_attr.override_redirect = True;
|
|
|
|
|
attr_mask |= CWOverrideRedirect;
|
|
|
|
|
|
|
|
|
|
nana::point pos(r.x, r.y);
|
|
|
|
|
win_attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask;
|
|
|
|
|
@@ -671,21 +793,21 @@ namespace nana{
|
|
|
|
|
{
|
|
|
|
|
::XMapWindow(disp, reinterpret_cast<Window>(wd));
|
|
|
|
|
|
|
|
|
|
auto i = exposed_positions.find(reinterpret_cast<Window>(wd));
|
|
|
|
|
if(i != exposed_positions.end())
|
|
|
|
|
{
|
|
|
|
|
::XMoveWindow(disp, reinterpret_cast<Window>(wd), i->second.x, i->second.y);
|
|
|
|
|
exposed_positions.erase(i);
|
|
|
|
|
}
|
|
|
|
|
//Wait for the mapping notify to update the local attribute of visibility so that
|
|
|
|
|
//the followed window_visible() call can return the updated visibility value.
|
|
|
|
|
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::map);
|
|
|
|
|
|
|
|
|
|
Window grab = restrict::spec.grab(0);
|
|
|
|
|
if(grab == reinterpret_cast<Window>(wd))
|
|
|
|
|
capture_window(wd, true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
|
|
|
|
|
|
|
|
|
|
::XFlush(disp);
|
|
|
|
|
//Wait for the mapping notify to update the local attribute of visibility so that
|
|
|
|
|
//the followed window_visible() call can return the updated visibility value.
|
|
|
|
|
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::unmap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static_cast<void>(active); //eliminate unused parameter compiler warning.
|
|
|
|
|
#endif
|
|
|
|
|
@@ -847,19 +969,24 @@ namespace nana{
|
|
|
|
|
}
|
|
|
|
|
return nana::point(r.left, r.top);
|
|
|
|
|
#elif defined(NANA_X11)
|
|
|
|
|
int x, y;
|
|
|
|
|
nana::detail::platform_scope_guard psg;
|
|
|
|
|
Window coord_wd = reinterpret_cast<Window>(restrict::spec.get_owner(wd));
|
|
|
|
|
if(!coord_wd)
|
|
|
|
|
point scr_pos;
|
|
|
|
|
nana::detail::platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
auto coord_wd = restrict::spec.get_owner(wd);
|
|
|
|
|
if(coord_wd)
|
|
|
|
|
{
|
|
|
|
|
coord_wd = reinterpret_cast<Window>(parent_window(wd));
|
|
|
|
|
if(!coord_wd)
|
|
|
|
|
coord_wd = restrict::spec.root_window();
|
|
|
|
|
//wd is a top level window. It returns the position of its decoration window.
|
|
|
|
|
auto decr = x11_parent_window(wd);
|
|
|
|
|
if(decr != coord_wd)
|
|
|
|
|
wd = decr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
coord_wd = get_window(wd, window_relationship::parent);
|
|
|
|
|
|
|
|
|
|
Window child;
|
|
|
|
|
if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast<Window>(wd), coord_wd, 0, 0, &x, &y, &child))
|
|
|
|
|
return nana::point(x, y);
|
|
|
|
|
return nana::point(0, 0);
|
|
|
|
|
::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast<Window>(wd), reinterpret_cast<Window>(coord_wd), 0, 0, &scr_pos.x, &scr_pos.y, &child);
|
|
|
|
|
|
|
|
|
|
return scr_pos;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -890,21 +1017,21 @@ namespace nana{
|
|
|
|
|
#elif defined(NANA_X11)
|
|
|
|
|
Display * disp = restrict::spec.open_display();
|
|
|
|
|
|
|
|
|
|
nana::detail::platform_scope_guard psg;
|
|
|
|
|
Window owner = reinterpret_cast<Window>(restrict::spec.get_owner(wd));
|
|
|
|
|
if(owner)
|
|
|
|
|
{
|
|
|
|
|
Window child;
|
|
|
|
|
::XTranslateCoordinates(disp, owner, restrict::spec.root_window(),
|
|
|
|
|
x, y, &x, &y, &child);
|
|
|
|
|
}
|
|
|
|
|
nana::detail::platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
|
|
|
|
if(attr.map_state == IsUnmapped)
|
|
|
|
|
exposed_positions[reinterpret_cast<Window>(wd)] = ::nana::point{x, y};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x11_revise_position(wd, x, y);
|
|
|
|
|
|
|
|
|
|
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
|
|
|
|
|
|
|
|
|
|
//Wait for the configuration notify to update the local attribute of position so that
|
|
|
|
|
//the followed window_position() call can return the updated position value.
|
|
|
|
|
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -954,16 +1081,6 @@ namespace nana{
|
|
|
|
|
else
|
|
|
|
|
hints.flags = 0;
|
|
|
|
|
|
|
|
|
|
Window owner = reinterpret_cast<Window>(restrict::spec.get_owner(wd));
|
|
|
|
|
int x = r.x;
|
|
|
|
|
int y = r.y;
|
|
|
|
|
if(owner)
|
|
|
|
|
{
|
|
|
|
|
Window child;
|
|
|
|
|
::XTranslateCoordinates(disp, owner, restrict::spec.root_window(),
|
|
|
|
|
r.x, r.y, &x, &y, &child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
|
|
|
|
if(attr.map_state == IsUnmapped)
|
|
|
|
|
@@ -972,13 +1089,24 @@ namespace nana{
|
|
|
|
|
hints.width = r.width;
|
|
|
|
|
hints.height = r.height;
|
|
|
|
|
|
|
|
|
|
exposed_positions[reinterpret_cast<Window>(wd)] = point{x, y};
|
|
|
|
|
exposed_positions[reinterpret_cast<Window>(wd)] = r.position();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(hints.flags)
|
|
|
|
|
::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints);
|
|
|
|
|
|
|
|
|
|
int x = r.x;
|
|
|
|
|
int y = r.y;
|
|
|
|
|
x11_revise_position(wd, x, y);
|
|
|
|
|
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
|
|
|
|
|
|
|
|
|
|
//Wait for the configuration notify to update the local attribute of position so that
|
|
|
|
|
//the followed window_position() call can return the updated position value.
|
|
|
|
|
|
|
|
|
|
//It seems that XMoveResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
|
|
|
|
|
//to make sure the local attribute is updated.
|
|
|
|
|
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
@@ -1096,6 +1224,10 @@ namespace nana{
|
|
|
|
|
::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints);
|
|
|
|
|
}
|
|
|
|
|
::XResizeWindow(disp, reinterpret_cast<Window>(wd), sz.width, sz.height);
|
|
|
|
|
|
|
|
|
|
//It seems that XResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
|
|
|
|
|
//to make sure the local attribute is updated.
|
|
|
|
|
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
@@ -1231,34 +1363,29 @@ namespace nana{
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
native_window_type native_interface::get_owner_window(native_window_type wd)
|
|
|
|
|
{
|
|
|
|
|
#if defined(NANA_WINDOWS)
|
|
|
|
|
return reinterpret_cast<native_window_type>(::GetWindow(reinterpret_cast<HWND>(wd), GW_OWNER));
|
|
|
|
|
#elif defined(NANA_X11)
|
|
|
|
|
return restrict::spec.get_owner(wd);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
native_window_type native_interface::parent_window(native_window_type wd)
|
|
|
|
|
native_window_type native_interface::get_window(native_window_type wd, window_relationship rsp)
|
|
|
|
|
{
|
|
|
|
|
#ifdef NANA_WINDOWS
|
|
|
|
|
return reinterpret_cast<native_window_type>(::GetParent(reinterpret_cast<HWND>(wd)));
|
|
|
|
|
if(window_relationship::either_po == rsp)
|
|
|
|
|
return reinterpret_cast<native_window_type>(::GetParent(reinterpret_cast<HWND>(wd)));
|
|
|
|
|
else if(window_relationship::parent == rsp)
|
|
|
|
|
return reinterpret_cast<native_window_type>(::GetAncestor(reinterpret_cast<HWND>(wd), GA_PARENT));
|
|
|
|
|
else if(window_relationship::owner == rsp)
|
|
|
|
|
return reinterpret_cast<native_window_type>(::GetWindow(reinterpret_cast<HWND>(wd), GW_OWNER));
|
|
|
|
|
#elif defined(NANA_X11)
|
|
|
|
|
Window root;
|
|
|
|
|
Window parent;
|
|
|
|
|
Window * children;
|
|
|
|
|
unsigned size;
|
|
|
|
|
|
|
|
|
|
platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast<Window>(wd),
|
|
|
|
|
&root, &parent, &children, &size))
|
|
|
|
|
auto owner = restrict::spec.get_owner(wd);
|
|
|
|
|
|
|
|
|
|
if(window_relationship::either_po == rsp)
|
|
|
|
|
{
|
|
|
|
|
::XFree(children);
|
|
|
|
|
return reinterpret_cast<native_window_type>(parent);
|
|
|
|
|
if(owner)
|
|
|
|
|
return owner;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
else if(window_relationship::owner == rsp)
|
|
|
|
|
return owner;
|
|
|
|
|
|
|
|
|
|
return x11_parent_window(wd);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1279,7 +1406,7 @@ namespace nana{
|
|
|
|
|
platform_scope_guard lock;
|
|
|
|
|
|
|
|
|
|
if(returns_previous)
|
|
|
|
|
prev = parent_window(child);
|
|
|
|
|
prev = get_window(child, window_relationship::either_po);
|
|
|
|
|
|
|
|
|
|
if(native_window_type{} == new_parent)
|
|
|
|
|
new_parent = reinterpret_cast<native_window_type>(restrict::spec.root_window());
|
|
|
|
|
|