[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16543] trunk/blender/intern/ghost/intern: Small fix in GHOST X11 system.

Diego Borghetti bdiego at gmail.com
Mon Sep 15 20:23:37 CEST 2008


Revision: 16543
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16543
Author:   bdiego
Date:     2008-09-15 20:23:34 +0200 (Mon, 15 Sep 2008)

Log Message:
-----------
Small fix in GHOST X11 system.

* Fix and a little of cleanup to the full screen, minimzed and
  maximized code.

* Fix bad argument in the ClientMessage event to support the
  _NET_ACTIVE_WINDOW property.

* Fix focus problem in some WM (like TWM), this is because Blender
  don't set the WM_PROTOCOLS list, now it does, a very basic list
  but it's what we need now.
 

Modified Paths:
--------------
    trunk/blender/intern/ghost/intern/GHOST_SystemX11.cpp
    trunk/blender/intern/ghost/intern/GHOST_SystemX11.h
    trunk/blender/intern/ghost/intern/GHOST_WindowX11.cpp
    trunk/blender/intern/ghost/intern/GHOST_WindowX11.h

Modified: trunk/blender/intern/ghost/intern/GHOST_SystemX11.cpp
===================================================================
--- trunk/blender/intern/ghost/intern/GHOST_SystemX11.cpp	2008-09-15 18:15:11 UTC (rev 16542)
+++ trunk/blender/intern/ghost/intern/GHOST_SystemX11.cpp	2008-09-15 18:23:34 UTC (rev 16543)
@@ -96,15 +96,26 @@
 	if (!m_display) return;
 	
 #ifdef __sgi
-	m_delete_window_atom 
-	  = XSGIFastInternAtom(m_display,
+	m_delete_window_atom = XSGIFastInternAtom(m_display,
 			       "WM_DELETE_WINDOW", 
 			       SGI_XA_WM_DELETE_WINDOW, False);
 #else
-	m_delete_window_atom 
-	  = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
+	m_delete_window_atom = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
 #endif
 
+	m_wm_protocols= XInternAtom(m_display, "WM_PROTOCOLS", False);
+	m_wm_take_focus= XInternAtom(m_display, "WM_TAKE_FOCUS", 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);
+
 	// compute the initial time
 	timeval tv;
 	if (gettimeofday(&tv,NULL) == -1) {
@@ -477,7 +488,7 @@
 			XClientMessageEvent & xcme = xe->xclient;
 
 #ifndef __sgi			
-			if (xcme.data.l[0] == m_delete_window_atom) {
+			if (((Atom)xcme.data.l[0]) == m_delete_window_atom) {
 				g_event = new 
 				GHOST_Event(	
 					getMilliSeconds(),
@@ -511,6 +522,14 @@
 					                              GHOST_kEventNDOFButton,
 					                              window, data);
 				}
+			}
+			else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
+				/* as ICCCM say, we need reply this event
+				 * with a SetInputFocus, the data[1] have
+				 * the valid timestamp (send by the window
+				 * manager).
+				 */
+				XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
 			} else {
 				/* Unknown client message, ignore */
 			}
@@ -528,6 +547,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: trunk/blender/intern/ghost/intern/GHOST_SystemX11.h
===================================================================
--- trunk/blender/intern/ghost/intern/GHOST_SystemX11.h	2008-09-15 18:15:11 UTC (rev 16542)
+++ trunk/blender/intern/ghost/intern/GHOST_SystemX11.h	2008-09-15 18:23:34 UTC (rev 16543)
@@ -215,15 +215,27 @@
 	 */
 	virtual void putClipboard(GHOST_TInt8 *buffer, int flag) const;
 
+	/**
+	 * 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_protocols;
+	Atom m_wm_take_focus;
+	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;
+	Atom m_delete_window_atom;
+
 private :
 
 	Display * m_display;
 
-	/**
-	 * Atom used to detect window close events
-	 */
-	Atom m_delete_window_atom;
-
 	/// The vector of windows that need to be updated.
 	std::vector<GHOST_WindowX11 *> m_dirty_windows;
 

Modified: trunk/blender/intern/ghost/intern/GHOST_WindowX11.cpp
===================================================================
--- trunk/blender/intern/ghost/intern/GHOST_WindowX11.cpp	2008-09-15 18:15:11 UTC (rev 16542)
+++ trunk/blender/intern/ghost/intern/GHOST_WindowX11.cpp	2008-09-15 18:23:34 UTC (rev 16543)
@@ -55,6 +55,16 @@
 #define MWM_HINTS_DECORATIONS         (1L << 1)
 
 /*
+ * A client can't change the window property, that is the
+ * work of the window manager. We send a ClientMessage
+ * event to the Root window 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
 
@@ -154,7 +164,8 @@
 	
 	// Set up the minimum atrributes that we require and see if
 	// X can find us a visual matching those requirements.
-
+	Atom atoms[2];
+	int natom;
 	int attributes[40], i = 0;
 	
 	
@@ -228,7 +239,6 @@
 		Window root_return;
 		int x_return,y_return;
 		unsigned int w_return,h_return,border_w_return,depth_return;
-		GHOST_TInt32 screen_x, screen_y;
 		
 		XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return,
 			&w_return, &h_return, &border_w_return, &depth_return );
@@ -262,46 +272,26 @@
 	// Are we in fullscreen mode - then include
 	// some obscure blut code to remove decorations.
 
-	if (state == GHOST_kWindowStateFullScreen) {
+	/*
+	 * 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
+	 * mapped 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;
+	}
 
-		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.	
 
@@ -324,7 +314,26 @@
 	free(wmclass);
 	XFree(xclasshint);
 
+	/* The basic for a good ICCCM "work" */
+	if (m_system->m_wm_protocols) {
+		natom= 0;
 
+		if (m_system->m_delete_window_atom) {
+			atoms[natom]= m_system->m_delete_window_atom;
+			natom++;
+		}
+
+		if (m_system->m_wm_take_focus) {
+			atoms[natom]= m_system->m_wm_take_focus;
+			natom++;
+		}
+
+		if (natom) {
+			/* printf("Register atoms: %d\n", natom); */
+			XSetWMProtocols(m_display, m_window, atoms, natom);
+		}
+	}
+
 	// Set the window icon
 	XWMHints *xwmhints = XAllocWMHints();
 	XImage *x_image, *mask_image;
@@ -645,28 +654,298 @@
 	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, i;
+	Atom type_ret;
+	bool st;
+	int format_ret, count;
+
+	prop_ret = NULL;
+	st = False;

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list