Posted to tcl by patthoyts at Mon Dec 07 15:27:53 GMT 2009view raw

  1. Fix extended window manager hints for Tk menus
  2. Also add a 'wm attributes . -type' option to apply a type hint to any
  3. Tk window from script. This is needed for tooltip windows, combobox
  4. dropdown windows and splash screens and probably others.
  5.  
  6. Not quite complete yet. Reading the hints back from the window
  7. need to do the reverse lookup still.
  8.  
  9. diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c
  10. index c4ec9af..fcdcac1 100644
  11. --- a/unix/tkUnixWm.c
  12. +++ b/unix/tkUnixWm.c
  13. @@ -52,12 +52,12 @@ typedef struct {
  14.  
  15. typedef enum {
  16. WMATT_ALPHA, WMATT_TOPMOST, WMATT_ZOOMED, WMATT_FULLSCREEN,
  17. - _WMATT_LAST_ATTRIBUTE
  18. + WMATT_TYPE, _WMATT_LAST_ATTRIBUTE
  19. } WmAttribute;
  20.  
  21. static const char *WmAttributeNames[] = {
  22. "-alpha", "-topmost", "-zoomed", "-fullscreen",
  23. - NULL
  24. + "-type", NULL
  25. };
  26.  
  27. /*
  28. @@ -347,6 +347,8 @@ static void UpdateTitle(TkWindow *winPtr);
  29. static void UpdatePhotoIcon(TkWindow *winPtr);
  30. static void UpdateVRootGeometry(WmInfo *wmPtr);
  31. static void UpdateWmProtocols(WmInfo *wmPtr);
  32. +static int SetNetWmType(TkWindow *winPtr, Tcl_Obj *typePtr);
  33. +static Tcl_Obj * GetNetWmType(TkWindow *winPtr);
  34. static void SetNetWmState(TkWindow*, const char *atomName, int on);
  35. static void CheckNetWmState(WmInfo *, Atom *atoms, int numAtoms);
  36. static void UpdateNetWmState(WmInfo *);
  37. @@ -1277,6 +1279,10 @@ WmSetAttribute(
  38. SetNetWmState(winPtr, "_NET_WM_STATE_ABOVE",
  39. wmPtr->reqState.topmost);
  40. break;
  41. + case WMATT_TYPE:
  42. + if (TCL_OK != SetNetWmType(winPtr, value))
  43. + return TCL_ERROR;
  44. + break;
  45. case WMATT_ZOOMED:
  46. if (TCL_OK != Tcl_GetBooleanFromObj(interp, value,
  47. &wmPtr->reqState.zoomed)) {
  48. @@ -1330,6 +1336,8 @@ WmGetAttribute(
  49. return Tcl_NewBooleanObj(wmPtr->attributes.zoomed);
  50. case WMATT_FULLSCREEN:
  51. return Tcl_NewBooleanObj(wmPtr->attributes.fullscreen);
  52. + case WMATT_TYPE:
  53. + return GetNetWmType(winPtr);
  54. case _WMATT_LAST_ATTRIBUTE: /*NOTREACHED*/
  55. break;
  56. }
  57. @@ -5325,6 +5333,108 @@ UpdateHints(
  58. XSetWMHints(winPtr->display, wmPtr->wrapperPtr->window, &wmPtr->hints);
  59. }
  60.  
  61. +struct ExwmhLookup {
  62. + const char *name;
  63. + const char *hint;
  64. +};
  65. +struct ExwmhLookup exwmh_map[] = {
  66. + { "desktop", "_NET_WM_WINDOW_TYPE_DESKTOP" },
  67. + { "dock", "_NET_WM_WINDOW_TYPE_DOCK" },
  68. + { "toolbar", "_NET_WM_WINDOW_TYPE_TOOLBAR" },
  69. + { "menu", "_NET_WM_WINDOW_TYPE_MENU" },
  70. + { "utility", "_NET_WM_WINDOW_TYPE_UTILITY" },
  71. + { "splash", "_NET_WM_WINDOW_TYPE_SPLASH" },
  72. + { "dialog", "_NET_WM_WINDOW_TYPE_DIALOG" },
  73. + { "dropdown", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
  74. + { "popup", "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
  75. + { "tooltip", "_NET_WM_WINDOW_TYPE_TOOLTIP" },
  76. + { "notification", "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
  77. + { "combo", "_NET_WM_WINDOW_TYPE_COMBO" },
  78. + { "dnd", "_NET_WM_WINDOW_TYPE_DND" },
  79. + { "normal", "_NET_WM_WINDOW_TYPE_NORMAL" },
  80. + { NULL, NULL }
  81. +};
  82. +
  83. +int
  84. +SetNetWmType(TkWindow *winPtr, Tcl_Obj *typePtr)
  85. +{
  86. + Atom typeAtom, *atoms;
  87. + WmInfo *wmPtr;
  88. + TkWindow *wrapperPtr;
  89. + Tcl_Obj **objv;
  90. + int objc, n, index;
  91. + Tk_Window tkwin = (Tk_Window)winPtr;
  92. + Tcl_Interp *interp = Tk_Interp(tkwin);
  93. +
  94. + if (TCL_OK != Tcl_ListObjGetElements(interp, typePtr, &objc, &objv)) {
  95. + return TCL_ERROR;
  96. + }
  97. +
  98. + if (objc == 0) {
  99. + return TCL_OK;
  100. + }
  101. +
  102. + if (!Tk_HasWrapper(tkwin)) {
  103. + return TCL_OK; /* error?? */
  104. + }
  105. +
  106. + atoms = (Atom *)ckalloc(sizeof(Atom) * objc);
  107. +
  108. + for (n = 0; n < objc; ++n) {
  109. + if (TCL_OK != Tcl_GetIndexFromObjStruct(interp, objv[n], exwmh_map,
  110. + sizeof(exwmh_map[0]), "type", 0, &index)) {
  111. + ckfree((char *)atoms);
  112. + return TCL_ERROR;
  113. + }
  114. + atoms[n] = Tk_InternAtom(tkwin, exwmh_map[index].hint);
  115. + }
  116. +
  117. + wmPtr = winPtr->wmInfoPtr;
  118. + if (wmPtr->wrapperPtr == NULL) {
  119. + CreateWrapper(wmPtr);
  120. + }
  121. + wrapperPtr = wmPtr->wrapperPtr;
  122. +
  123. + typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE");
  124. + XChangeProperty(Tk_Display(tkwin), wrapperPtr->window, typeAtom,
  125. + XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, objc);
  126. +
  127. + ckfree((char *)atoms);
  128. + return TCL_OK;
  129. +}
  130. +
  131. +Tcl_Obj *
  132. +GetNetWmType(TkWindow *winPtr)
  133. +{
  134. + Atom typeAtom, actualType, *atoms;
  135. + int actualFormat;
  136. + unsigned long n, count, bytesAfter;
  137. + unsigned char *propertyValue = NULL;
  138. + long maxLength = 1024;
  139. + Tk_Window tkwin = (Tk_Window)winPtr;
  140. + TkWindow *wrapperPtr = winPtr->wmInfoPtr->wrapperPtr;
  141. + Tcl_Obj *typePtr;
  142. + Tcl_Interp *interp;
  143. +
  144. + interp = Tk_Interp(tkwin);
  145. + typePtr = Tcl_NewListObj(0, NULL);
  146. +
  147. + typeAtom = Tk_InternAtom(tkwin, "_NET_WM_WINDOW_TYPE");
  148. + if (Success == XGetWindowProperty(wrapperPtr->display,
  149. + wrapperPtr->window, typeAtom, 0L, maxLength, False,
  150. + XA_ATOM, &actualType, &actualFormat, &count,
  151. + &bytesAfter, &propertyValue)) {
  152. + atoms = (Atom *)propertyValue;
  153. + for (n = 0; n < count; ++n) {
  154. + Tcl_ListObjAppendElement(interp, typePtr,
  155. + Tcl_NewStringObj(Tk_GetAtomName(tkwin, atoms[n]), -1));
  156. + }
  157. + XFree(propertyValue);
  158. + }
  159. +
  160. + return typePtr;
  161. +}
  162. +
  163. /*
  164. *--------------------------------------------------------------
  165. *
  166. @@ -6599,6 +6709,19 @@ GetMaxSize(
  167. }
  168. }
  169.  
  170. +void
  171. +TkSetTransientFor(Tk_Window tkwin, Tk_Window parent)
  172. +{
  173. + if (parent == NULL) {
  174. + parent = Tk_Parent(tkwin);
  175. + while (!Tk_IsTopLevel(parent))
  176. + parent = Tk_Parent(tkwin);
  177. + }
  178. + XSetTransientForHint(Tk_Display(tkwin),
  179. + ((TkWindow *)tkwin)->wmInfoPtr->wrapperPtr->window,
  180. + ((TkWindow *)parent)->wmInfoPtr->wrapperPtr->window);
  181. +}
  182. +
  183. /*
  184. *----------------------------------------------------------------------
  185. *
  186. @@ -6628,6 +6751,7 @@ TkpMakeMenuWindow(
  187. WmInfo *wmPtr;
  188. XSetWindowAttributes atts;
  189. TkWindow *wrapperPtr;
  190. + Atom atom;
  191.  
  192. if (!Tk_HasWrapper(tkwin)) {
  193. return;
  194. @@ -6640,10 +6764,17 @@ TkpMakeMenuWindow(
  195. if (transient) {
  196. atts.override_redirect = True;
  197. atts.save_under = True;
  198. + atom = Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
  199. } else {
  200. atts.override_redirect = False;
  201. atts.save_under = False;
  202. + atom = Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE_MENU");
  203. + TkSetTransientFor(tkwin, NULL);
  204. }
  205. + XChangeProperty(Tk_Display(tkwin), wrapperPtr->window,
  206. + Tk_InternAtom((Tk_Window) tkwin, "_NET_WM_WINDOW_TYPE"),
  207. + XA_ATOM, 32, PropModeReplace,
  208. + (unsigned char *) &atom, 1);
  209.  
  210. /*
  211. * The override-redirect and save-under bits must be set on the wrapper