Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Borghetti <bdiego@gmail.com>2008-01-04 00:04:16 +0300
committerDiego Borghetti <bdiego@gmail.com>2008-01-04 00:04:16 +0300
commit350d754b16b97f56fb02765bc35178d2ad2d7415 (patch)
tree9d9259cc460403787865ff3d57c29524aef74280 /intern/ghost
parentc87785671ca1a9c6ec91b0af19c77aba1b42c2b5 (diff)
Add support for GHOST_kWindowState* to Linux.
This add support for the different window state in Linux/X11. Two think to take care: 1) m_post_* 2) motifFullScreen 1) This is only need if we want start a window in FullScreen or Maximized state. The basic problem is that we can't set this property to a window until it's really map, so i add a "post init" proccess for this two special case (check the code for more info). 2) The Motif Hint isn't really a "FullScreen" mode, it's only a "NO DECORATIONS" options, so if the window manager don't support WM-spec this function only remove the border of the window, don't make it FullScreen. A simple fix (hack) is check if the Window Manager support WM-spec, in case that not, remove the decorations and move/resize the window. Test in different WM (gnome, kde, etc) and comment are welcome :)
Diffstat (limited to 'intern/ghost')
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp39
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h13
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp373
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h21
4 files changed, 386 insertions, 60 deletions
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 14383ad3624..e02131498e4 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -113,9 +113,26 @@ GHOST_SystemX11(
= XSGIFastInternAtom(m_display,
"WM_DELETE_WINDOW",
SGI_XA_WM_DELETE_WINDOW, False);
+ /* Some one with SGI can tell me about this ? */
+ m_wm_state= None;
+ m_wm_change_state= None;
+ m_net_state= None;
+ m_net_max_horz= None;
+ m_net_max_vert= None;
+ m_net_fullscreen= None;
+ m_motif = None;
#else
- m_delete_window_atom
- = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
+ m_delete_window_atom= XInternAtom(m_display, "WM_DELETE_WINDOW", False);
+ m_wm_state= XInternAtom(m_display, "WM_STATE", False);
+ m_wm_change_state= XInternAtom(m_display, "WM_CHANGE_STATE", False);
+ m_net_state= XInternAtom(m_display, "_NET_WM_STATE", False);
+ m_net_max_horz= XInternAtom(m_display,
+ "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ m_net_max_vert= XInternAtom(m_display,
+ "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ m_net_fullscreen= XInternAtom(m_display,
+ "_NET_WM_STATE_FULLSCREEN", False);
+ m_motif= XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
#endif
// compute the initial time
@@ -499,6 +516,24 @@ GHOST_SystemX11::processEvent(XEvent *xe)
// XCrossingEvents pointer leave enter window.
break;
case MapNotify:
+ /*
+ * From ICCCM:
+ * [ Clients can select for StructureNotify on their
+ * top-level windows to track transition between
+ * Normal and Iconic states. Receipt of a MapNotify
+ * event will indicate a transition to the Normal
+ * state, and receipt of an UnmapNotify event will
+ * indicate a transition to the Iconic state. ]
+ */
+ if (window->m_post_init == True) {
+ /*
+ * Now we are sure that the window is
+ * mapped, so only need change the state.
+ */
+ window->setState (window->m_post_state);
+ window->m_post_init = False;
+ }
+ break;
case UnmapNotify:
break;
case MappingNotify:
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index c8d8d73404a..0763238ea61 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -196,6 +196,19 @@ public:
return m_display;
}
+ /**
+ * Atom used for ICCCM, WM-spec and Motif.
+ * We only need get this atom at the start, it's relative
+ * to the display not the window and are public for every
+ * window that need it.
+ */
+ Atom m_wm_state;
+ Atom m_wm_change_state;
+ Atom m_net_state;
+ Atom m_net_max_horz;
+ Atom m_net_max_vert;
+ Atom m_net_fullscreen;
+ Atom m_motif;
private :
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 544222e814f..f40f70eb24d 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -56,6 +56,16 @@ typedef struct {
#define MWM_HINTS_DECORATIONS (1L << 1)
/*
+ * A Client can't change the window property, that is
+ * the work of the window manager. In case, we send
+ * a ClientMessage to the RootWindow with the property
+ * and the Action (WM-spec define this):
+ */
+#define _NET_WM_STATE_REMOVE 0
+#define _NET_WM_STATE_ADD 1
+#define _NET_WM_STATE_TOGGLE 2
+
+/*
import bpy
I = bpy.data.images['blender.png'] # the 48x48 icon
@@ -222,49 +232,25 @@ GHOST_WindowX11(
&xattributes
);
-
- // Are we in fullscreen mode - then include
- // some obscure blut code to remove decorations.
-
- if (state == GHOST_kWindowStateFullScreen) {
-
- MotifWmHints hints;
- Atom atom;
-
- atom = XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
-
- if (atom == None) {
- GHOST_PRINT("Could not intern X atom for _MOTIF_WM_HINTS.\n");
- } else {
- hints.flags = MWM_HINTS_DECORATIONS;
- hints.decorations = 0; /* Absolutely no decorations. */
- // other hints.decorations make no sense
- // you can't select individual decorations
-
- XChangeProperty(m_display, m_window,
- atom, atom, 32,
- PropModeReplace, (unsigned char *) &hints, 4);
- }
- } else if (state == GHOST_kWindowStateMaximized) {
- // With this, xprop should report the following just after launch
- // _NET_WM_STATE(ATOM) = _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ
- // After demaximization the right side is empty, though (maybe not the most correct then?)
- Atom state, atomh, atomv;
-
- state = XInternAtom(m_display, "_NET_WM_STATE", False);
- atomh = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
- atomv = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
- if (state == None ) {
- GHOST_PRINT("Atom _NET_WM_STATE requested but not avaliable nor created.\n");
- } else {
- XChangeProperty(m_display, m_window,
- state, XA_ATOM, 32,
- PropModeAppend, (unsigned char *) &atomh, 1);
- XChangeProperty(m_display, m_window,
- state, XA_ATOM, 32,
- PropModeAppend, (unsigned char *) &atomv, 1);
- }
- }
+ /*
+ * One of the problem with WM-spec is that can't set a property
+ * to a window that isn't mapped. That is why we can't "just
+ * call setState" here.
+ *
+ * To fix this, we first need know that the window is really
+ * map waiting for the MapNotify event.
+ *
+ * So, m_post_init indicate that we need wait for the MapNotify
+ * event and then set the Window state to the m_post_state.
+ */
+ if ((state != GHOST_kWindowStateNormal) && (state != GHOST_kWindowStateMinimized)) {
+ m_post_init = True;
+ m_post_state = state;
+ }
+ else {
+ m_post_init = False;
+ m_post_state = GHOST_kWindowStateNormal;
+ }
// Create some hints for the window manager on how
// we want this window treated.
@@ -609,28 +595,299 @@ clientToScreen(
outY = ay;
}
+void GHOST_WindowX11::icccmSetState(int state)
+{
+ XEvent xev;
- GHOST_TWindowState
-GHOST_WindowX11::
-getState(
-) const {
- //FIXME
- return GHOST_kWindowStateNormal;
+ if (state != IconicState)
+ return;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = m_display;
+ xev.xclient.window = m_window;
+ xev.xclient.format = 32;
+ xev.xclient.message_type = m_system->m_wm_change_state;
+ xev.xclient.data.l[0] = state;
+ XSendEvent (m_display, RootWindow(m_display, DefaultScreen(m_display)),
+ False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
}
- GHOST_TSuccess
-GHOST_WindowX11::
-setState(
- GHOST_TWindowState state
-){
- //TODO
+int GHOST_WindowX11::icccmGetState(void) const
+{
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+ Atom type_ret;
+ int format_ret, st;
+
+ prop_ret = NULL;
+ st = XGetWindowProperty(m_display, m_window, m_system->m_wm_state, 0,
+ 0x7fffffff, False, m_system->m_wm_state, &type_ret,
+ &format_ret, &num_ret, &bytes_after, &prop_ret);
+
+ if ((st == Success) && (prop_ret) && (num_ret == 2))
+ st = prop_ret[0];
+ else
+ st = NormalState;
+
+ if (prop_ret)
+ XFree(prop_ret);
+ return (st);
+}
+
+void GHOST_WindowX11::netwmMaximized(bool set)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = m_window;
+ xev.xclient.message_type = m_system->m_net_state;
+ xev.xclient.format = 32;
+
+ if (set == True)
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ else
+ xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+
+ xev.xclient.data.l[1] = m_system->m_net_max_horz;
+ xev.xclient.data.l[2] = m_system->m_net_max_vert;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+ XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)),
+ False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+bool GHOST_WindowX11::netwmIsMaximized(void) const
+{
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+ Atom type_ret;
+ bool st;
+ int format_ret, count, i;
+
+ prop_ret = NULL;
+ st = False;
+ i = XGetWindowProperty(m_display, m_window, m_system->m_net_state, 0,
+ 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret,
+ &num_ret, &bytes_after, &prop_ret);
+ if ((i == Success) && (prop_ret) && (format_ret == 32)) {
+ count = 0;
+ for (i = 0; i < num_ret; i++) {
+ if (((unsigned long *) prop_ret)[i] == m_system->m_net_max_horz)
+ count++;
+ if (((unsigned long *) prop_ret)[i] == m_system->m_net_max_vert)
+ count++;
+ if (count == 2) {
+ st = True;
+ break;
+ }
+ }
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+ return (st);
+}
+
+void GHOST_WindowX11::netwmFullScreen(bool set)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = m_window;
+ xev.xclient.message_type = m_system->m_net_state;
+ xev.xclient.format = 32;
+
+ if (set == True)
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ else
+ xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+
+ xev.xclient.data.l[1] = m_system->m_net_fullscreen;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+ XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)),
+ False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+bool GHOST_WindowX11::netwmIsFullScreen(void) const
+{
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+ Atom type_ret;
+ bool st;
+ int format_ret, i;
+
+ prop_ret = NULL;
+ st = False;
+ i = XGetWindowProperty(m_display, m_window, m_system->m_net_state, 0,
+ 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret,
+ &num_ret, &bytes_after, &prop_ret);
+ if ((i == Success) && (prop_ret) && (format_ret == 32)) {
+ for (i = 0; i < num_ret; i++) {
+ if (((unsigned long *) prop_ret)[i] == m_system->m_net_fullscreen) {
+ st = True;
+ break;
+ }
+ }
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+ return (st);
+}
+
+void GHOST_WindowX11::motifFullScreen(bool set)
+{
+ MotifWmHints hints;
+
+ hints.flags = MWM_HINTS_DECORATIONS;
+ if (set == True)
+ hints.decorations = 0;
+ else
+ hints.decorations = 1;
+
+ XChangeProperty(m_display, m_window, m_system->m_motif,
+ m_system->m_motif, 32, PropModeReplace,
+ (unsigned char *) &hints, 4);
+}
+
+bool GHOST_WindowX11::motifIsFullScreen(void) const
+{
+ unsigned char *prop_ret;
+ unsigned long bytes_after, num_ret;
+ MotifWmHints *hints;
+ Atom type_ret;
+ bool state;
+ int format_ret, st;
+
+ prop_ret = NULL;
+ state = False;
+ st = XGetWindowProperty(m_display, m_window, m_system->m_motif, 0,
+ 0x7fffffff, False, m_system->m_motif,
+ &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret);
+ if ((st == Success) && (prop_ret)) {
+ hints = (MotifWmHints *) prop_ret;
+ if (hints->flags & MWM_HINTS_DECORATIONS) {
+ if (!hints->decorations)
+ state = True;
+ }
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+ return (state);
+}
- if (state == (int)getState()) {
+GHOST_TWindowState GHOST_WindowX11::getState() const
+{
+ GHOST_TWindowState state_ret;
+ int state;
+
+ state_ret = GHOST_kWindowStateNormal;
+ state = icccmGetState();
+ /*
+ * In the Iconic and Withdrawn state, the window
+ * is unmaped, so only need return a Minimized state.
+ */
+ if ((state == IconicState) || (state == WithdrawnState))
+ state_ret = GHOST_kWindowStateMinimized;
+ else if (netwmIsMaximized() == True)
+ state_ret = GHOST_kWindowStateMaximized;
+ else if (netwmIsFullScreen() == True)
+ state_ret = GHOST_kWindowStateFullScreen;
+ else if (motifIsFullScreen() == True)
+ state_ret = GHOST_kWindowStateFullScreen;
+ return (state_ret);
+}
+
+GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
+{
+ GHOST_TWindowState cur_state;
+ bool is_max, is_full, is_motif_full;
+ int icccm_state;
+
+ cur_state = getState();
+ if (state == (int)cur_state)
return GHOST_kSuccess;
- } else {
- return GHOST_kFailure;
+
+ if (cur_state != GHOST_kWindowStateMinimized) {
+ /*
+ * The window don't have this property's
+ * if it's not mapped.
+ */
+ is_max = netwmIsMaximized();
+ is_full = netwmIsFullScreen();
+ }
+ else {
+ is_max = False;
+ is_full = False;
+ }
+
+ is_motif_full = motifIsFullScreen();
+
+ if (state == GHOST_kWindowStateNormal) {
+ if (is_max == True)
+ netwmMaximized(False);
+ if (is_full == True)
+ netwmFullScreen(False);
+ if (is_motif_full == True)
+ motifFullScreen(False);
+ icccmSetState(NormalState);
+ return (GHOST_kSuccess);
+ }
+
+ if (state == GHOST_kWindowStateFullScreen) {
+ /*
+ * We can't change to full screen if the window
+ * isn't mapped.
+ */
+ if (cur_state == GHOST_kWindowStateMinimized)
+ return (GHOST_kFailure);
+
+ if (is_max == True)
+ netwmMaximized(False);
+ if (is_full == False)
+ netwmFullScreen(True);
+ if (is_motif_full == False)
+ motifFullScreen(True);
+ return (GHOST_kSuccess);
+ }
+
+ if (state == GHOST_kWindowStateMaximized) {
+ /*
+ * We can't change to Maximized if the window
+ * isn't mapped.
+ */
+ if (cur_state == GHOST_kWindowStateMinimized)
+ return (GHOST_kFailure);
+
+ if (is_full == True)
+ netwmFullScreen(False);
+ if (is_motif_full == True)
+ motifFullScreen(False);
+ if (is_max == False)
+ netwmMaximized(True);
+ return (GHOST_kSuccess);
+ }
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /*
+ * The window manager need save the current state of
+ * the window (maximized, full screen, etc).
+ */
+ icccmSetState(IconicState);
+ return (GHOST_kSuccess);
}
+ return (GHOST_kFailure);
}
#include <iostream>
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 0de4f65acd1..0acf5532829 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -213,6 +213,15 @@ public:
const GHOST_TabletData* GetTabletData()
{ return &m_xtablet.CommonData; }
+
+ /*
+ * Need this in case that we want start the window
+ * in FullScree or Maximized state.
+ * Check GHOST_WindowX11.cpp
+ */
+ bool m_post_init;
+ GHOST_TWindowState m_post_state;
+
protected:
/**
* Tries to install a rendering context in this window.
@@ -328,6 +337,18 @@ private :
/* Tablet devices */
XTablet m_xtablet;
+
+ void icccmSetState(int state);
+ int icccmGetState() const;
+
+ void netwmMaximized(bool set);
+ bool netwmIsMaximized() const;
+
+ void netwmFullScreen(bool set);
+ bool netwmIsFullScreen() const;
+
+ void motifFullScreen(bool set);
+ bool motifIsFullScreen() const;
};