[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [13116] branches/blender2.5/blender/intern /ghost/intern: Add support for GHOST_kWindowState* to Linux.

Diego Borghetti (Plumiferos) bdiego at gmail.com
Thu Jan 3 22:04:16 CET 2008


Revision: 13116
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=13116
Author:   bdiego
Date:     2008-01-03 22:04:16 +0100 (Thu, 03 Jan 2008)

Log Message:
-----------
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 :)

Modified Paths:
--------------
    branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.cpp
    branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.h
    branches/blender2.5/blender/intern/ghost/intern/GHOST_WindowX11.cpp
    branches/blender2.5/blender/intern/ghost/intern/GHOST_WindowX11.h

Modified: branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.cpp
===================================================================
--- branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.cpp	2008-01-03 20:53:42 UTC (rev 13115)
+++ branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.cpp	2008-01-03 21:04:16 UTC (rev 13116)
@@ -113,9 +113,26 @@
 	  = 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 @@
 			// 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:

Modified: branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.h
===================================================================
--- branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.h	2008-01-03 20:53:42 UTC (rev 13115)
+++ branches/blender2.5/blender/intern/ghost/intern/GHOST_SystemX11.h	2008-01-03 21:04:16 UTC (rev 13116)
@@ -196,6 +196,19 @@
 		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 :
 

Modified: branches/blender2.5/blender/intern/ghost/intern/GHOST_WindowX11.cpp
===================================================================
--- branches/blender2.5/blender/intern/ghost/intern/GHOST_WindowX11.cpp	2008-01-03 20:53:42 UTC (rev 13115)
+++ branches/blender2.5/blender/intern/ghost/intern/GHOST_WindowX11.cpp	2008-01-03 21:04:16 UTC (rev 13116)
@@ -56,6 +56,16 @@
 #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,50 +232,26 @@
 			&xattributes
 		);
 	
+	/*
+	 * 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;
+	}
 	
-	// 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);
-		}
- 	}
-	
 	// Create some hints for the window manager on how
 	// we want this window treated.	
 
@@ -609,28 +595,299 @@
 	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;
 
-        if (state == (int)getState()) {
+	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,

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list