Home > Uncategorized > Removing decorations in Metacity

Removing decorations in Metacity

I switched to gnome and I miss one wonderful feature of kwin. By combining always on top and remove decoration, kwin allow to transform any window into a kind of post-it embedded into an other window. For example I use it to add an xterm in Netbeans. I don’t know any other window manager than kwin being able to hide decoration with a hot key.

From Devil’s pie source code I found that it was possible to remove decoration using the _MOTIF_WM_HINTS window property. It first tried it with the xprop command, but I had some trouble to handle the maximized window case. Then I found the Ralf Neupert wmctrl patch. I used it as inspiration to write my wmctrl patch, which toggle decoration and ensure that maximized window spread on the whole screen. See the patch bellow.

Metacity have a built-in support for binding custom action to shortcut. In gconf-editor:

  • /apps/metacity/keybinding_commands/command_1 = wmctrl -r :ACTIVE: -B
  • /apps/metacity/global_keybindings/run_command_1 = <mod4>H

A first implementation in shell script using the xprop command. It doesn’t handle the maximized window case.

#! /bin/sh -x
winid=$(xprop -root | awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}')
current=$(xprop -id $winid | awk '/_MOTIF_WM_HINTS/ { sub(/,/,"",$5); print $5 }')
if [ -z $current ]; then
    current=0;
else
    current=$((1-$current))
fi

xprop -id $winid -f _MOTIF_WM_HINTS 32c -set _MOTIF_WM_HINTS "0x2, 0x0, $current, 0x0, 0x0"

This is a patch to wmctrl, adapted from Ralf one. It ensure that window keep it’s maximized status:

--- /tmp/wmctrl-1.07/main.c	2009-05-22 19:58:19.000000000 +0200
+++ main.c	2009-04-12 16:51:40.000000000 +0200
@@ -264,7 +264,7 @@
         }
     }
    
-    while ((opt = getopt(argc, argv, "FGVvhlupidmxa:r:s:c:t:w:k:o:n:g:e:b:N:I:T:R:")) != -1) {
+    while ((opt = getopt(argc, argv, "BFGVvhlupidmxa:r:s:c:t:w:k:o:n:g:e:b:N:I:T:R:")) != -1) {
         missing_option = 0;
         switch (opt) {
             case 'F':
@@ -356,7 +356,7 @@
             ret = wm_info(disp);
             break;
         case 'a': case 'c': case 'R': 
-        case 't': case 'e': case 'b': case 'N': case 'I': case 'T':
+	case 't': case 'e': case 'b': case 'N': case 'I': case 'T': case 'B':
             if (! options.param_window) {
                 fputs("No window was specified.\n", stderr);
                 return EXIT_FAILURE;
@@ -874,6 +874,83 @@
     }
 }/*}}}*/
 
+static int switch_decoration (Display *disp, Window win) {
+    #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+    #define MWM_HINTS_DECORATIONS (1L << 1)
+    struct {
+        unsigned long flags;
+        unsigned long functions;
+        unsigned long decorations;
+        long inputMode;
+        unsigned long status;
+    } hints = {0,};
+
+    Atom mA = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
+    Atom sA = XInternAtom(disp, "_NET_WM_STATE", False);
+    //Atom maximizedHorzAtom = XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+    Atom maximizedVertAtom = XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+    Atom actual_type_return;
+    int actual_format_return;
+    int max=0;
+    int i;
+    unsigned long nitems_return;
+    unsigned long bytes_after_return;
+    unsigned long *prop_return;
+    int x, y, junkx, junky;
+    unsigned int wwidth, wheight, bw, depth;
+    Window junkroot;
+
+    //check if the window is maxmized
+    XGetWindowProperty(disp, win, sA, 0, PROP_MOTIF_WM_HINTS_ELEMENTS, 0,
+        AnyPropertyType, &actual_type_return, &actual_format_return,
+        &nitems_return, &bytes_after_return, &prop_return);
+
+    for(i = 0; i < nitems_return; i++)
+    {
+        if(prop_return[i] == maximizedVertAtom)
+            max = 1;
+    }
+
+    //get the window size
+    XGetGeometry (disp, win, &junkroot, &junkx, &junky,
+                      &wwidth, &wheight, &bw, &depth);
+    XTranslateCoordinates (disp, win, junkroot, junkx, junky,
+                           &x, &y, &junkroot);
+    wwidth += junkx;
+    wheight += junky;
+
+    //check the decoration stats
+    XGetWindowProperty(disp, win, mA, 0, PROP_MOTIF_WM_HINTS_ELEMENTS, 0, mA,
+        &actual_type_return, &actual_format_return, &nitems_return,
+        &bytes_after_return, &prop_return);
+
+    if(nitems_return >= 3)
+        hints.decorations = 1 ^ prop_return[2];
+    else
+        hints.decorations = 0;
+   
+    //fix the window size so it does'nt move after removing the border
+    if(!max)
+    {
+        if(!hints.decorations)
+            XMoveWindow(disp, win, x+junkx, y+junky);
+        else
+            XMoveWindow(disp, win, x-junkx, y-junky);
+    }
+
+    // show/hide borders
+    hints.flags = MWM_HINTS_DECORATIONS;
+    XChangeProperty(disp, win, mA, mA, 32, PropModeReplace,
+        (unsigned char *)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
+
+    //Ensure the window is still maximized
+    if(max)
+        XResizeWindow(disp, win, wwidth, wheight);
+
+    activate_window (disp, win, 0);
+    return EXIT_SUCCESS;
+}
+
 static int action_window (Display *disp, Window win, char mode) {/*{{{*/
     p_verbose("Using window: 0x%.8lx\n", win);
     switch (mode) {
@@ -909,7 +986,8 @@
         case 'N': case 'I': case 'T':
             window_set_title(disp, win, options.param, mode);
             return EXIT_SUCCESS;
-
+        case 'B':
+	    return switch_decoration(disp, win);
         default:
             fprintf(stderr, "Unknown action: '%c'\n", mode);
             return EXIT_FAILURE;
Advertisements
  1. Chris
    May 21, 2009 at 15:08

    Hi, I compiled wmctrl 1.07 with your patch but failed.

    Here is the message, I’m using Gentoo with gcc 4.4 and gcc 4.3.3.
    Thanks!

    main.c:672: warning: pointer targets in passing argument 7 of ‘XChangeProperty’ differ in signedness
    /usr/include/X11/Xlib.h:2086: note: expected ‘const unsigned char *’ but argument is of type ‘gchar *’
    main.c: In function ‘switch_decoration’:
    main.c:906: warning: passing argument 12 of ‘XGetWindowProperty’ from incompatible pointer type
    /usr/include/X11/Xlib.h:2694: note: expected ‘unsigned char **’ but argument is of type ‘long unsigned int **’
    main.c:908: warning: suggest parentheses around assignment used as truth value
    main.c:910: error: ‘else’ without a previous ‘if’
    main.c:901: warning: unused variable ‘junkroot’
    main.c:900: warning: unused variable ‘depth’
    main.c:900: warning: unused variable ‘bw’
    main.c:891: warning: unused variable ‘maximizedVertAtom’
    make: *** [main.o] Error 1
    *
    * ERROR: x11-misc/wmctrl-1.07-r1 failed.
    * Call stack:
    * ebuild.sh, line 49: Called src_compile
    * environment, line 2267: Called _eapi0_src_compile
    * ebuild.sh, line 600: Called _eapi2_src_compile
    * ebuild.sh, line 634: Called die
    * The specific snippet of code:
    * emake || die “emake failed”
    * The die message:
    * emake failed
    *
    * If you need support, post the topmost build error, and the call stack if relevant.
    * A complete build log is located at ‘/data/tmp/portage/x11-misc/wmctrl-1.07-r1/temp/build.log’.
    * The ebuild environment file is located at ‘/data/tmp/portage/x11-misc/wmctrl-1.07-r1/temp/environment’.
    *

  2. xrunhprof
    May 21, 2009 at 18:20

    Oops my patch was messed up after the c/c in WordPress. The operators were interpreted as HTML tags. I will fix this tomorow or the day after.

  3. Chris
    May 22, 2009 at 06:34

    Hi, just report back, removed following lines from patch and got wmctrl compiled.

    + for(i = 0; i = 3)
    + hints.decorations = 1 ^ prop_return[2];
    + else
    + hints.decorations = 0;

    I think it works now, Thank you!

    But I still have a problem, it might have nothing to do with your patch.

    I’m using gnome and metacity, wmctrl -B could remove the decoration of the window, but if I switch to another workspace then switch back, decoration get restored.

    I tried devilspie, same behavior.

    Thanks again.

  4. xrunhprof
    May 22, 2009 at 18:14

    I didn’t notice this problem as I only use one desktop. Anyway I fixed the patch.

  5. Chris
    May 24, 2009 at 13:38

    I recompiled wmctrl again, and seems -B didn’t remove decoration anymore…
    The window just don’t change.
    And I didn’t keep your old patch so I am not sure what’s the problem, could you verify that?

    Thank you.

  6. Rob
    November 11, 2009 at 19:04

    I updated the patch for wmctrl-1.07-6 in Ubuntu Karmic Koala:

    — wmctrl-1.07/main.c 2009-11-11 14:01:01.000000000 -0500
    +++ wmctrl-1.07-patched/main.c 2009-11-11 13:58:30.000000000 -0500
    @@ -264,7 +264,7 @@
    }
    }

    – while ((opt = getopt(argc, argv, “FGVvhlupidmxa:r:s:c:t:w:k:o:n:g:e:b:N:I:T:R:”)) != -1) {
    + while ((opt = getopt(argc, argv, “BFGVvhlupidmxa:r:s:c:t:w:k:o:n:g:e:b:N:I:T:R:”)) != -1) {
    missing_option = 0;
    switch (opt) {
    case ‘F’:
    @@ -356,7 +356,7 @@
    ret = wm_info(disp);
    break;
    case ‘a’: case ‘c’: case ‘R’:
    – case ‘t’: case ‘e’: case ‘b’: case ‘N’: case ‘I’: case ‘T’:
    + case ‘t’: case ‘e’: case ‘b’: case ‘N’: case ‘I’: case ‘T’: case ‘B’:
    if (! options.param_window) {
    fputs(“No window was specified.\n”, stderr);
    return EXIT_FAILURE;
    @@ -874,6 +874,85 @@
    }
    }/*}}}*/

    +static int switch_decoration (Display *disp, Window win) {
    + #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
    + #define MWM_HINTS_DECORATIONS (1L << 1)
    + struct {
    + unsigned long flags;
    + unsigned long functions;
    + unsigned long decorations;
    + long inputMode;
    + unsigned long status;
    + } hints = {0,};
    +
    + Atom mA = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
    + Atom sA = XInternAtom(disp, "_NET_WM_STATE", False);
    + //Atom maximizedHorzAtom = XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
    + Atom maximizedVertAtom = XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_VERT", False);
    + Atom actual_type_return;
    + int actual_format_return;
    + int max=0;
    + int i;
    + unsigned long nitems_return;
    + unsigned long bytes_after_return;
    + unsigned long *prop_return;
    + int x, y, junkx, junky;
    + unsigned int wwidth, wheight, bw, depth;
    + Window junkroot;
    +
    + //check if the window is maxmized
    + XGetWindowProperty(disp, win, sA, 0, PROP_MOTIF_WM_HINTS_ELEMENTS, 0,
    + AnyPropertyType, &actual_type_return, &actual_format_return,
    + &nitems_return, &bytes_after_return, &prop_return);
    +
    + for(i = 0; i = 3)
    + hints.decorations = 1 ^ prop_return[2];
    + else
    + hints.decorations = 0;
    +
    + //fix the window size so it does’nt move after removing the border
    + if(!max)
    + {
    + if(!hints.decorations)
    + // For some reason removing the border needs to move the
    + // window left as well.
    + XMoveWindow(disp, win, x-junkx, y-junky);
    + else
    + XMoveWindow(disp, win, x-junkx, y-junky);
    + }
    +
    + // show/hide borders
    + hints.flags = MWM_HINTS_DECORATIONS;
    + XChangeProperty(disp, win, mA, mA, 32, PropModeReplace,
    + (unsigned char *)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
    +
    + //Ensure the window is still maximized
    + if(max)
    + XResizeWindow(disp, win, wwidth, wheight);
    +
    + activate_window (disp, win, 0);
    + return EXIT_SUCCESS;
    +}
    +
    static int action_window (Display *disp, Window win, char mode) {/*{{{*/
    p_verbose(“Using window: 0x%.8lx\n”, win);
    switch (mode) {
    @@ -909,7 +988,8 @@
    case ‘N’: case ‘I’: case ‘T’:
    window_set_title(disp, win, options.param, mode);
    return EXIT_SUCCESS;

    + case ‘B’:
    + return switch_decoration(disp, win);
    default:
    fprintf(stderr, “Unknown action: ‘%c’\n”, mode);
    return EXIT_FAILURE;

  7. Ole Brustad
    January 13, 2010 at 20:51

    Tanks for a super tip!
    I just cut-n-pasted the script, and it worked perfectly in
    Gnome, Metacity, Ubuntu Karmic on a Acer Aspire One.
    (to increase performance I have killed the launcher and maximus…)

  8. February 18, 2010 at 00:55

    Interesting. Have you discussed getting your patch integrated with the wmctl author?

  9. tdignan1
    April 17, 2012 at 23:24

    Thank you for the xprop script! Exactly what I was looking for.

  10. masa winner
    September 18, 2012 at 06:03

    Your patch is smart addition to wmctrl. I wonder why it hasn’t been admitted into the mainstream distribution. BTW it’s a life saver in gnome 3.x and gnome 3.x classic (fallback), where up to 3.4 at least, the keybinding for ‘above’ does not work. The same goes for the Mate desktop v. 1.4.

  11. Spotter
    September 15, 2013 at 08:40

    Obviously one comes across this page quickly when searcing the internet for “removing window manager decorations” … I just noticed, in MATE 1.6, this function is integrated, it just doesn’t have a hotkey by default, but you can simply define one with MATE’s included hotkey setup program

  1. February 3, 2010 at 23:41
  2. February 4, 2010 at 04:41
  3. September 3, 2012 at 09:28
  4. September 10, 2012 at 03:47
  5. September 10, 2012 at 03:49
  6. May 19, 2014 at 16:58

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: