Tk Source Code

Artifact [77af8b96]
Login

Artifact 77af8b968a50fccc9a5158fc8762c20ee723693b:

Attachment "ewmh.patch" to ticket [2918731f] added by dkf 2009-12-21 22:25:04.
diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c
index c4ec9af..fcdcac1 100644
--- a/unix/tkUnixWm.c
+++ b/unix/tkUnixWm.c
@@ -52,12 +52,12 @@ typedef struct {
 
 typedef enum {
     WMATT_ALPHA, WMATT_TOPMOST, WMATT_ZOOMED, WMATT_FULLSCREEN,
-    _WMATT_LAST_ATTRIBUTE
+    WMATT_TYPE, _WMATT_LAST_ATTRIBUTE
 } WmAttribute;
 
 static const char *WmAttributeNames[] = {
     "-alpha", "-topmost", "-zoomed", "-fullscreen",
-    NULL
+    "-type", NULL
 };
 
 /*
@@ -347,6 +347,8 @@ static void		UpdateTitle(TkWindow *winPtr);
 static void		UpdatePhotoIcon(TkWindow *winPtr);
 static void		UpdateVRootGeometry(WmInfo *wmPtr);
 static void		UpdateWmProtocols(WmInfo *wmPtr);
+static int		SetNetWmType(TkWindow *winPtr, Tcl_Obj *typePtr);
+static Tcl_Obj *	GetNetWmType(TkWindow *winPtr);
 static void 		SetNetWmState(TkWindow*, const char *atomName, int on);
 static void 		CheckNetWmState(WmInfo *, Atom *atoms, int numAtoms);
 static void 		UpdateNetWmState(WmInfo *);
@@ -1277,6 +1279,10 @@ WmSetAttribute(
 	SetNetWmState(winPtr, "_NET_WM_STATE_ABOVE",
 		wmPtr->reqState.topmost);
 	break;
+    case WMATT_TYPE:
+	if (TCL_OK != SetNetWmType(winPtr, value))
+	    return TCL_ERROR;
+	break;
     case WMATT_ZOOMED:
 	if (TCL_OK != Tcl_GetBooleanFromObj(interp, value,
 		&wmPtr->reqState.zoomed)) {
@@ -1330,6 +1336,8 @@ WmGetAttribute(
 	return Tcl_NewBooleanObj(wmPtr->attributes.zoomed);
     case WMATT_FULLSCREEN:
 	return Tcl_NewBooleanObj(wmPtr->attributes.fullscreen);
+    case WMATT_TYPE:
+	return GetNetWmType(winPtr);
     case _WMATT_LAST_ATTRIBUTE:	/*NOTREACHED*/
 	break;
     }
@@ -5325,6 +5333,108 @@ UpdateHints(
     XSetWMHints(winPtr->display, wmPtr->wrapperPtr->window, &wmPtr->hints);
 }
  
+struct ExwmhLookup {
+    const char *name;
+    const char *hint;
+};
+struct ExwmhLookup exwmh_map[] = {
+    { "desktop", "_NET_WM_WINDOW_TYPE_DESKTOP" },
+    { "dock", "_NET_WM_WINDOW_TYPE_DOCK" },
+    { "toolbar", "_NET_WM_WINDOW_TYPE_TOOLBAR" },
+    { "menu", "_NET_WM_WINDOW_TYPE_MENU" },
+    { "utility", "_NET_WM_WINDOW_TYPE_UTILITY" },
+    { "splash", "_NET_WM_WINDOW_TYPE_SPLASH" },
+    { "dialog", "_NET_WM_WINDOW_TYPE_DIALOG" },
+    { "dropdown", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
+    { "popup", "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
+    { "tooltip", "_NET_WM_WINDOW_TYPE_TOOLTIP" },
+    { "notification", "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
+    { "combo", "_NET_WM_WINDOW_TYPE_COMBO" },
+    { "dnd", "_NET_WM_WINDOW_TYPE_DND" },
+    { "normal", "_NET_WM_WINDOW_TYPE_NORMAL" },
+    { NULL, NULL }
+};
+
+int
+SetNetWmType(TkWindow *winPtr, Tcl_Obj *typePtr)
+{
+    Atom typeAtom, *atoms;
+    WmInfo *wmPtr;
+    TkWindow *wrapperPtr;
+    Tcl_Obj **objv;
+    int objc, n, index;
+    Tk_Window tkwin = (Tk_Window)winPtr;
+    Tcl_Interp *interp = Tk_Interp(tkwin);
+
+    if (TCL_OK != Tcl_ListObjGetElements(interp, typePtr, &objc, &objv)) {
+	return TCL_ERROR;
+    }
+
+    if (objc == 0) {
+	return TCL_OK;
+    }
+
+    if (!Tk_HasWrapper(tkwin)) {
+	return TCL_OK; /* error?? */
+    }
+
+    atoms = (Atom *)ckalloc(sizeof(Atom) * objc);
+    
+    for (n = 0; n < objc; ++n) {
+	if (TCL_OK != Tcl_GetIndexFromObjStruct(interp, objv[n], exwmh_map,
+		sizeof(exwmh_map[0]), "type", 0, &index)) {
+	    ckfree((char *)atoms);
+	    return TCL_ERROR;
+	}
+	atoms[n] = Tk_InternAtom(tkwin, exwmh_map[index].hint);
+    }
+
+    wmPtr = winPtr->wmInfoPtr;
+    if (wmPtr->wrapperPtr == NULL) {
+	CreateWrapper(wmPtr);
+    }
+    wrapperPtr = wmPtr->wrapperPtr;
+
+    typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE");
+    XChangeProperty(Tk_Display(tkwin), wrapperPtr->window, typeAtom,
+	XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, objc);
+
+    ckfree((char *)atoms);
+    return TCL_OK;
+}
+ 
+Tcl_Obj *
+GetNetWmType(TkWindow *winPtr)
+{
+    Atom typeAtom, actualType, *atoms;
+    int actualFormat;
+    unsigned long n, count, bytesAfter;
+    unsigned char *propertyValue = NULL;
+    long maxLength = 1024;
+    Tk_Window tkwin = (Tk_Window)winPtr;
+    TkWindow *wrapperPtr = winPtr->wmInfoPtr->wrapperPtr;
+    Tcl_Obj *typePtr;
+    Tcl_Interp *interp;
+
+    interp = Tk_Interp(tkwin);
+    typePtr = Tcl_NewListObj(0, NULL);
+
+    typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE");
+    if (Success == XGetWindowProperty(wrapperPtr->display,
+	    wrapperPtr->window, typeAtom, 0L, maxLength, False,
+	    XA_ATOM, &actualType, &actualFormat, &count,
+	    &bytesAfter, &propertyValue)) {
+	atoms = (Atom *)propertyValue;
+	for (n = 0; n < count; ++n) {
+	    Tcl_ListObjAppendElement(interp, typePtr,
+		Tcl_NewStringObj(Tk_GetAtomName(tkwin, atoms[n]), -1));
+	}
+	XFree(propertyValue);
+    }
+
+    return typePtr;
+}
+ 
 /*
  *--------------------------------------------------------------
  *
@@ -6599,6 +6709,19 @@ GetMaxSize(
     }
 }
  
+void
+TkSetTransientFor(Tk_Window tkwin, Tk_Window parent)
+{
+    if (parent == NULL) {
+	parent = Tk_Parent(tkwin);
+	while (!Tk_IsTopLevel(parent))
+	    parent = Tk_Parent(tkwin);
+    }
+    XSetTransientForHint(Tk_Display(tkwin),
+                         ((TkWindow *)tkwin)->wmInfoPtr->wrapperPtr->window,
+                         ((TkWindow *)parent)->wmInfoPtr->wrapperPtr->window);
+}
+ 
 /*
  *----------------------------------------------------------------------
  *
@@ -6628,6 +6751,7 @@ TkpMakeMenuWindow(
     WmInfo *wmPtr;
     XSetWindowAttributes atts;
     TkWindow *wrapperPtr;
+    Atom atom;
 
     if (!Tk_HasWrapper(tkwin)) {
 	return;
@@ -6640,10 +6764,17 @@ TkpMakeMenuWindow(
     if (transient) {
 	atts.override_redirect = True;
 	atts.save_under = True;
+	atom = Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
     } else {
 	atts.override_redirect = False;
 	atts.save_under = False;
+	atom = Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE_MENU");
+	TkSetTransientFor(tkwin, NULL);
     }
+    XChangeProperty(Tk_Display(tkwin), wrapperPtr->window,
+    Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE"),
+	XA_ATOM, 32, PropModeReplace,
+	(unsigned char *) &atom, 1);
 
     /*
      * The override-redirect and save-under bits must be set on the wrapper