JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
merge upstream jason
authorJason Woofenden <jason@jasonwoof.com>
Sun, 19 Oct 2014 18:49:50 +0000 (14:49 -0400)
committerJason Woofenden <jason@jasonwoof.com>
Sun, 19 Oct 2014 18:49:50 +0000 (14:49 -0400)
1  2 
spectrwm.c
spectrwm.conf

diff --combined spectrwm.c
@@@ -331,6 -331,7 +331,7 @@@ bool                       cycle_visible = false
  int                   term_width = 0;
  int                   font_adjusted = 0;
  unsigned int          mod_key = MODKEY;
+ bool                  warp_pointer = false;
  
  /* dmenu search */
  struct swm_region     *search_r;
@@@ -367,7 -368,7 +368,7 @@@ enum 
  /* dialog windows */
  double                        dialog_ratio = 0.6;
  /* status bar */
 -#define SWM_BAR_MAX           (256)
 +#define SWM_BAR_MAX           (356)
  #define SWM_BAR_JUSTIFY_LEFT  (0)
  #define SWM_BAR_JUSTIFY_CENTER        (1)
  #define SWM_BAR_JUSTIFY_RIGHT (2)
@@@ -401,9 -402,7 +402,10 @@@ bool               stack_enabled = true
  bool           clock_enabled = true;
  bool           iconic_enabled = false;
  bool           urgent_enabled = false;
 +int            composite_enabled = 0;
 +double                 opacity_focus = 1.0;
 +double                 opacity_unfocus = 0.6;
+ bool           urgent_collapse = false;
  char          *clock_format = NULL;
  bool           window_class_enabled = false;
  bool           window_instance_enabled = false;
@@@ -481,7 -480,7 +483,7 @@@ struct ws_win 
        bool                    can_delete;
        bool                    take_focus;
        bool                    java;
-       unsigned long           quirks;
+       uint32_t                quirks;
        struct workspace        *ws;    /* always valid */
        struct swm_screen       *s;     /* always valid, never changes */
        xcb_size_hints_t        sh;
@@@ -520,7 -519,7 +522,7 @@@ struct layout 
  } layouts[] =  {
        /* stack,               configure */
        { vertical_stack,       vertical_config,        0,      plain_stacker },
 -      { horizontal_stack,     horizontal_config,      0,      plain_stacker },
 +//    { horizontal_stack,     horizontal_config,      0,      plain_stacker },
        { max_stack,            NULL,
          SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV,                   plain_stacker },
        { NULL,                 NULL,                   0,      NULL  },
  /* position of max_stack mode in the layouts array, index into layouts! */
  #define SWM_V_STACK           (0)
  #define SWM_H_STACK           (1)
 -#define SWM_MAX_STACK         (2)
 +#define SWM_MAX_STACK         (1)
  
  #define SWM_H_SLICE           (32)
  #define SWM_V_SLICE           (32)
@@@ -665,7 -664,8 +667,8 @@@ struct quirk 
        regex_t                 regex_class;
        regex_t                 regex_instance;
        regex_t                 regex_name;
-       unsigned long           quirk;
+       uint32_t                quirk;
+       int                     ws;             /* Initial workspace. */
  #define SWM_Q_FLOAT           (1<<0)  /* float this window */
  #define SWM_Q_TRANSSZ         (1<<1)  /* transiend window size too small */
  #define SWM_Q_ANYWHERE                (1<<2)  /* don't position this window */
@@@ -713,7 -713,6 +716,7 @@@ enum 
        _NET_WM_STATE_MAXIMIZED_HORZ,
        _NET_WM_STATE_SKIP_PAGER,
        _NET_WM_STATE_SKIP_TASKBAR,
 +      _NET_WM_WINDOW_OPACITY,
        _NET_WM_WINDOW_TYPE,
        _NET_WM_WINDOW_TYPE_DIALOG,
        _NET_WM_WINDOW_TYPE_DOCK,
@@@ -757,7 -756,6 +760,7 @@@ struct ewmh_hint 
      {"_NET_WM_STATE_MAXIMIZED_HORZ", XCB_ATOM_NONE},
      {"_NET_WM_STATE_SKIP_PAGER", XCB_ATOM_NONE},
      {"_NET_WM_STATE_SKIP_TASKBAR", XCB_ATOM_NONE},
 +    {"_NET_WM_WINDOW_OPACITY", XCB_ATOM_NONE},
      {"_NET_WM_WINDOW_TYPE", XCB_ATOM_NONE},
      {"_NET_WM_WINDOW_TYPE_DIALOG", XCB_ATOM_NONE},
      {"_NET_WM_WINDOW_TYPE_DOCK", XCB_ATOM_NONE},
@@@ -969,6 -967,7 +972,7 @@@ void        bar_window_name(char *, size_t, s
  void   bar_window_state(char *, size_t, struct swm_region *);
  void   bar_workspace_name(char *, size_t, struct swm_region *);
  void   buttonpress(xcb_button_press_event_t *);
+ void   center_pointer(struct swm_region *);
  void   check_conn(void);
  void   clear_keys(void);
  int    clear_maximized(struct workspace *);
@@@ -1042,6 -1041,7 +1046,7 @@@ char    *get_source_type_label(uint32_t)
  char  *get_stack_mode_name(uint8_t);
  #endif
  int32_t        get_swm_ws(xcb_window_t);
+ bool   get_urgent(struct ws_win *);
  char  *get_win_name(xcb_window_t);
  uint8_t        get_win_state(xcb_window_t);
  void   get_wm_protocols(struct ws_win *);
@@@ -1077,7 -1077,7 +1082,7 @@@ uint32_t name_to_pixel(int, const char 
  void   name_workspace(struct swm_region *, union arg *);
  void   new_region(struct swm_screen *, int, int, int, int);
  int    parsekeys(const char *, unsigned int, unsigned int *, KeySym *);
- int    parsequirks(const char *, unsigned long *);
+ int    parsequirks(const char *, uint32_t *, int *);
  int    parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *);
  void   pressbutton(struct swm_region *, union arg *);
  void   priorws(struct swm_region *, union arg *);
@@@ -1086,10 -1086,10 +1091,10 @@@ void  print_win_geom(xcb_window_t)
  #endif
  void   propertynotify(xcb_property_notify_event_t *);
  void   quirk_free(struct quirk *);
- void   quirk_insert(const char *, const char *, const char *,unsigned long);
+ void   quirk_insert(const char *, const char *, const char *, uint32_t, int);
  void   quirk_remove(struct quirk *);
  void   quirk_replace(struct quirk *, const char *, const char *, const char *,
-            unsigned long);
+            uint32_t, int);
  void   quit(struct swm_region *, union arg *);
  void   raise_toggle(struct swm_region *, union arg *);
  void   raise_window(struct ws_win *);
@@@ -1124,7 -1124,7 +1129,7 @@@ int      setconfvalue(const char *, const c
  void   setkeybinding(unsigned int, KeySym, enum keyfuncid, const char *);
  int    setkeymapping(const char *, const char *, int);
  int    setlayout(const char *, const char *, int);
- void   setquirk(const char *, const char *, const char *,unsigned long);
+ void   setquirk(const char *, const char *, const char *, uint32_t, int);
  void   setscreencolor(const char *, int, int);
  void   setspawn(const char *, const char *, int);
  void   setup_ewmh(void);
@@@ -1134,7 -1134,6 +1139,7 @@@ void     setup_quirks(void)
  void   setup_screens(void);
  void   setup_spawn(void);
  void   set_child_transient(struct ws_win *, xcb_window_t *);
 +void   set_opacity(struct ws_win *, uint32_t);
  void   set_win_state(struct ws_win *, uint8_t);
  void   shutdown_cleanup(void);
  void   sighdlr(int);
@@@ -2170,6 -2169,22 +2175,22 @@@ bar_window_name(char *s, size_t sz, str
        free(title);
  }
  
+ bool
+ get_urgent(struct ws_win *win)
+ {
+       xcb_icccm_wm_hints_t            hints;
+       xcb_get_property_cookie_t       c;
+       bool                            urgent = false;
+       if (win) {
+               c = xcb_icccm_get_wm_hints(conn, win->id);
+               if (xcb_icccm_get_wm_hints_reply(conn, c, &hints, NULL))
+                       urgent = xcb_icccm_wm_hints_get_urgency(&hints);
+       }
+       return urgent;
+ }
  void
  bar_urgent(char *s, size_t sz)
  {
        int                     i, j, num_screens;
        bool                    urgent[SWM_WS_MAX];
        char                    b[8];
-       xcb_get_property_cookie_t       c;
-       xcb_icccm_wm_hints_t    hints;
  
        for (i = 0; i < workspace_limit; i++)
                urgent[i] = false;
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                for (j = 0; j < workspace_limit; j++)
-                       TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) {
-                               c = xcb_icccm_get_wm_hints(conn, win->id);
-                               if (xcb_icccm_get_wm_hints_reply(conn, c,
-                                   &hints, NULL) == 0)
-                                       continue;
-                               if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY)
-                                       urgent[j] = true;
-                       }
+                       TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+                               urgent[j] = get_urgent(win);
  
        for (i = 0; i < workspace_limit; i++) {
-               if (urgent[i])
+               if (urgent[i]) {
                        snprintf(b, sizeof b, "%d ", i + 1);
-               else
-                       snprintf(b, sizeof b, "- ");
-               strlcat(s, b, sz);
+                       strlcat(s, b, sz);
+               } else if (!urgent_collapse) {
+                       strlcat(s, "- ", sz);
+               }
        }
  }
  
@@@ -3212,6 -3220,26 +3226,26 @@@ get_pointer_win(xcb_window_t root
        return win;
  }
  
+ void
+ center_pointer(struct swm_region *r)
+ {
+       struct ws_win                   *win;
+       if (!warp_pointer || r == NULL)
+               return;
+       win = r->ws->focus;
+       DNPRINTF(SWM_D_EVENT, "center_pointer: win %#x.\n", WINID(win));
+       if (win && win->mapped)
+               xcb_warp_pointer(conn, XCB_NONE, win->id, 0, 0, 0, 0,
+                   WIDTH(win) / 2, HEIGHT(win) / 2);
+       else
+               xcb_warp_pointer(conn, XCB_NONE, r->id, 0, 0, 0, 0,
+                   WIDTH(r) / 2, HEIGHT(r) / 2);
+ }
  struct swm_region *
  root_to_region(xcb_window_t root, int check)
  {
@@@ -3442,19 -3470,6 +3476,19 @@@ validate_ws(struct workspace *testws
        return (1);
  }
  
 +#define OPAQUE                0xffffffff
 +void
 +set_opacity(struct ws_win *win, uint32_t opacity)
 +{
 +      if (opacity != OPAQUE)
 +              xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
 +                  ewmh[_NET_WM_WINDOW_OPACITY].atom, XCB_ATOM_CARDINAL, 32, 1,
 +                  &opacity);
 +      else
 +              xcb_delete_property(conn, win->id,
 +                  ewmh[_NET_WM_WINDOW_OPACITY].atom);
 +}
 +
  void
  unfocus_win(struct ws_win *win)
  {
@@@ -3542,10 -3557,6 +3576,10 @@@ focus_win(struct ws_win *win
                                    &cfw->s->c[(MAXIMIZED(cfw) ?
                                    SWM_S_COLOR_UNFOCUS_MAXIMIZED :
                                    SWM_S_COLOR_UNFOCUS)].pixel);
 +
 +                              if (composite_enabled)
 +                                      set_opacity(cfw,
 +                                          opacity_unfocus * OPAQUE);
                        } else {
                                unfocus_win(cfw);
                        }
@@@ -3846,6 -3857,7 +3880,7 @@@ switchws(struct swm_region *r, union ar
  
        ewmh_update_current_desktop();
  
+       center_pointer(r);
        focus_flush();
        new_ws->state = SWM_WS_STATE_MAPPED;
  
@@@ -3942,6 -3954,7 +3977,7 @@@ focusrg(struct swm_region *r, union ar
                return;
  
        focus_region(rr);
+       center_pointer(rr);
        focus_flush();
        DNPRINTF(SWM_D_FOCUS, "focusrg: done\n");
  }
@@@ -3978,6 -3991,7 +4014,7 @@@ cyclerg(struct swm_region *r, union ar
                return;
  
        focus_region(rr);
+       center_pointer(rr);
        focus_flush();
        DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n");
  }
@@@ -4111,6 -4125,7 +4148,7 @@@ swapwin(struct swm_region *r, union ar
        ewmh_update_client_list();
  
        stack();
+       center_pointer(r);
        focus_flush();
  out:
        DNPRINTF(SWM_D_MOVE, "swapwin: done\n");
@@@ -4264,7 -4279,6 +4302,6 @@@ focus(struct swm_region *r, union arg *
        struct workspace        *ws = NULL;
        union arg               a;
        int                     i;
-       xcb_icccm_wm_hints_t    hints;
  
        if (!(r && r->ws))
                goto out;
  
                winfocus = TAILQ_FIRST(wl);
                if (winfocus == cur_focus)
 -                      winfocus = cur_focus->ws->focus_prev;
 +                      return;
                break;
        case SWM_ARG_ID_FOCUSURGENT:
                /* Search forward for the next urgent window. */
                                head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) %
                                    workspace_limit].winlist);
  
-                       while (head != NULL &&
-                           (head = TAILQ_NEXT(head, entry)) != NULL) {
+                       while (head) {
                                if (head == cur_focus) {
-                                       winfocus = cur_focus;
-                                       break;
-                               }
-                               if (xcb_icccm_get_wm_hints_reply(conn,
-                                   xcb_icccm_get_wm_hints(conn, head->id),
-                                   &hints, NULL) != 0 &&
-                                   xcb_icccm_wm_hints_get_urgency(&hints)) {
+                                       if (i > 0) {
+                                               winfocus = cur_focus;
+                                               break;
+                                       }
+                               } else if (get_urgent(head)) {
                                        winfocus = head;
                                        break;
                                }
+                               head = TAILQ_NEXT(head, entry);
                        }
  
-                       if (winfocus != NULL)
+                       if (winfocus)
                                break;
                }
  
                /* Switch ws if new focus is on a different ws. */
-               if (winfocus != NULL && winfocus->ws != ws) {
+               if (winfocus && winfocus->ws != ws) {
                        a.id = winfocus->ws->idx;
                        switchws(r, &a);
                }
                stack();
  
        focus_win(get_focus_magic(winfocus));
+       center_pointer(r);
        focus_flush();
  
  out:
@@@ -4397,6 -4411,7 +4434,7 @@@ cycle_layout(struct swm_region *r, unio
  
        focus_win(get_region_focus(r));
  
+       center_pointer(r);
        focus_flush();
  }
  
@@@ -4418,6 -4433,7 +4456,7 @@@ stack_config(struct swm_region *r, unio
                stack();
        bar_draw();
  
+       center_pointer(r);
        focus_flush();
  }
  
@@@ -4781,7 -4797,7 +4820,7 @@@ stack_master(struct workspace *ws, stru
                        win_g.y += last_h + 2 * border_width + tile_gap;
  
                if (disable_border && !(bar_enabled && ws->bar_enabled) &&
-                   winno == 1){
+                   winno == 1) {
                        bordered = false;
                        win_g.w += 2 * border_width;
                        win_g.h += 2 * border_width;
@@@ -4994,12 -5010,13 +5033,13 @@@ max_stack(struct workspace *ws, struct 
                if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w ||
                    HEIGHT(w) != gg.h) {
                        w->g = gg;
-                       if (bar_enabled && ws->bar_enabled){
-                               w->bordered = true;
-                       } else {
+                       if (disable_border && !(bar_enabled && ws->bar_enabled)) {
                                w->bordered = false;
                                WIDTH(w) += 2 * border_width;
                                HEIGHT(w) += 2 * border_width;
+                       } else {
+                               w->bordered = true;
                        }
  
                        update_window(w);
@@@ -5129,6 -5146,7 +5169,7 @@@ send_to_ws(struct swm_region *r, union 
                }
        }
  
+       center_pointer(r);
        focus_flush();
  }
  
@@@ -5944,6 -5962,7 +5985,7 @@@ maximize_toggle(struct swm_region *r, u
        if (w == w->ws->focus)
                focus_win(w);
  
+       center_pointer(r);
        focus_flush();
        DNPRINTF(SWM_D_MISC, "maximize_toggle: done\n");
  }
@@@ -5975,6 -5994,7 +6017,7 @@@ floating_toggle(struct swm_region *r, u
        if (w == w->ws->focus)
                focus_win(w);
  
+       center_pointer(r);
        focus_flush();
        DNPRINTF(SWM_D_MISC, "floating_toggle: done\n");
  }
@@@ -6071,22 -6091,15 +6114,22 @@@ update_window_color(struct ws_win *win
  {
        uint32_t        *pixel;
  
 -      if (WS_FOCUSED(win->ws) && win->ws->focus == win)
 +      if (WS_FOCUSED(win->ws) && win->ws->focus == win) {
                pixel = MAXIMIZED(win) ?
                    &win->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].pixel :
                    &win->s->c[SWM_S_COLOR_FOCUS].pixel;
 -      else
 +
 +              if (composite_enabled)
 +                      set_opacity(win, opacity_focus * OPAQUE);
 +      } else {
                pixel = MAXIMIZED(win) ?
                    &win->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].pixel :
                    &win->s->c[SWM_S_COLOR_UNFOCUS].pixel;
  
 +              if (composite_enabled)
 +                      set_opacity(win, opacity_unfocus * OPAQUE);
 +      }
 +
        xcb_change_window_attributes(conn, win->id,
            XCB_CW_BORDER_PIXEL, pixel);
  }
@@@ -6330,6 -6343,7 +6373,7 @@@ resize_step(struct swm_region *r, unio
                return;
  
        resize(win, args);
+       center_pointer(r);
        focus_flush();
  }
  
@@@ -6529,6 -6543,7 +6573,7 @@@ move_step(struct swm_region *r, union a
                return;
  
        move(win, args);
+       center_pointer(r);
        focus_flush();
  }
  
@@@ -7589,10 -7604,10 +7634,10 @@@ const char *quirkname[] = 
        "IGNORESPAWNWS",
  };
  
- /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
- #define SWM_Q_WS              "\n|+ \t"
+ /* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */
+ #define SWM_Q_DELIM           "\n|+ \t"
  int
- parsequirks(const char *qstr, unsigned long *quirk)
+ parsequirks(const char *qstr, uint32_t *quirk, int *ws)
  {
        char                    *str, *cp, *name;
        int                     i;
  
        cp = str;
        *quirk = 0;
-       while ((name = strsep(&cp, SWM_Q_WS)) != NULL) {
+       while ((name = strsep(&cp, SWM_Q_DELIM)) != NULL) {
                if (cp)
-                       cp += (long)strspn(cp, SWM_Q_WS);
+                       cp += (long)strspn(cp, SWM_Q_DELIM);
+               if (sscanf(name, "WS[%d]", ws) == 1) {
+                       if (*ws > 0)
+                               *ws -= 1;
+                       continue;
+               }
                for (i = 0; i < LENGTH(quirkname); i++) {
                        if (strncasecmp(name, quirkname[i],
                            SWM_QUIRK_LEN) == 0) {
  
  void
  quirk_insert(const char *class, const char *instance, const char *name,
-     unsigned long quirk)
+     uint32_t quirk, int ws)
  {
        struct quirk            *qp;
        char                    *str;
        bool                    failed = false;
  
        DNPRINTF(SWM_D_QUIRK, "quirk_insert: class: %s, instance: %s, name: %s,"
-           " value: %lu\n", class, instance, name, quirk);
+           " value: %u, ws: %d\n", class, instance, name, quirk, ws);
  
        if ((qp = malloc(sizeof *qp)) == NULL)
                err(1, "quirk_insert: malloc");
                quirk_free(qp);
        } else {
                qp->quirk = quirk;
+               qp->ws = ws;
                TAILQ_INSERT_TAIL(&quirks, qp, entry);
        }
        DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n");
  void
  quirk_remove(struct quirk *qp)
  {
-       DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class,
+       DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%u]\n", qp->class,
            qp->name, qp->quirk);
  
        TAILQ_REMOVE(&quirks, qp, entry);
@@@ -7721,43 -7744,44 +7774,44 @@@ quirk_free(struct quirk *qp
  
  void
  quirk_replace(struct quirk *qp, const char *class, const char *instance,
-     const char *name, unsigned long quirk)
+     const char *name, uint32_t quirk, int ws)
  {
-       DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%lu]\n", qp->class,
-           qp->instance, qp->name, qp->quirk);
+       DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%u], ws: %d\n", qp->class,
+           qp->instance, qp->name, qp->quirk, qp->ws);
  
        quirk_remove(qp);
-       quirk_insert(class, instance, name, quirk);
+       quirk_insert(class, instance, name, quirk, ws);
  
        DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n");
  }
  
  void
  setquirk(const char *class, const char *instance, const char *name,
-     unsigned long quirk)
+     uint32_t quirk, int ws)
  {
        struct quirk            *qp;
  
-       DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%lu]\n", class,
-           instance, name, quirk);
+       DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%u], ws: %d\n", class,
+           instance, name, quirk, ws);
  
        /* Remove/replace existing quirk. */
        TAILQ_FOREACH(qp, &quirks, entry) {
                if (strcmp(qp->class, class) == 0 &&
                    strcmp(qp->instance, instance) == 0 &&
                    strcmp(qp->name, name) == 0) {
-                       if (quirk == 0)
+                       if (quirk == 0 && ws == -1)
                                quirk_remove(qp);
                        else
-                               quirk_replace(qp, class, instance, name, quirk);
+                               quirk_replace(qp, class, instance, name, quirk,
+                                   ws);
                        DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
                        return;
                }
        }
  
-       /* Only insert if quirk is not NONE. */
-       if (quirk)
-               quirk_insert(class, instance, name, quirk);
+       /* Only insert if quirk is not NONE or forced ws is set. */
+       if (quirk || ws != -1)
+               quirk_insert(class, instance, name, quirk, ws);
  
        DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
  }
@@@ -7783,8 -7807,8 +7837,8 @@@ setconfquirk(const char *selector, cons
  {
        char                    *str, *cp, *class;
        char                    *instance = NULL, *name = NULL;
-       int                     retval, count = 0;
-       unsigned long           qrks;
+       int                     retval, count = 0, ws = -1;
+       uint32_t                qrks;
  
        /* suppress unused warning since var is needed */
        (void)flags;
        DNPRINTF(SWM_D_CONF, "setconfquirk: class: %s, instance: %s, "
            "name: %s\n", class, instance, name);
  
-       if ((retval = parsequirks(value, &qrks)) == 0)
-               setquirk(class, instance, name, qrks);
+       if ((retval = parsequirks(value, &qrks, &ws)) == 0)
+               setquirk(class, instance, name, qrks, ws);
  
        free(str);
        return (retval);
  void
  setup_quirks(void)
  {
-       setquirk("MPlayer",             "xv",           ".*",   SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV);
-       setquirk("OpenOffice.org 3.2",  "VCLSalFrame",  ".*",   SWM_Q_FLOAT);
-       setquirk("Firefox-bin",         "firefox-bin",  ".*",   SWM_Q_TRANSSZ);
-       setquirk("Firefox",             "Dialog",       ".*",   SWM_Q_FLOAT);
-       setquirk("Gimp",                "gimp",         ".*",   SWM_Q_FLOAT | SWM_Q_ANYWHERE);
-       setquirk("XTerm",               "xterm",        ".*",   SWM_Q_XTERM_FONTADJ);
-       setquirk("xine",                "Xine Window",  ".*",   SWM_Q_FLOAT | SWM_Q_ANYWHERE);
-       setquirk("Xitk",                "Xitk Combo",   ".*",   SWM_Q_FLOAT | SWM_Q_ANYWHERE);
-       setquirk("xine",                "xine Panel",   ".*",   SWM_Q_FLOAT | SWM_Q_ANYWHERE);
-       setquirk("Xitk",                "Xine Window",  ".*",   SWM_Q_FLOAT | SWM_Q_ANYWHERE);
-       setquirk("xine",                "xine Video Fullscreen Window", ".*",   SWM_Q_FULLSCREEN | SWM_Q_FLOAT);
-       setquirk("pcb",                 "pcb",          ".*",   SWM_Q_FLOAT);
-       setquirk("SDL_App",             "SDL_App",      ".*",   SWM_Q_FLOAT | SWM_Q_FULLSCREEN);
+       setquirk("MPlayer",             "xv",           ".*",
+           SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV, -1);
+       setquirk("OpenOffice.org 3.2",  "VCLSalFrame",  ".*",
+           SWM_Q_FLOAT, -1);
+       setquirk("Firefox-bin",         "firefox-bin",  ".*",
+           SWM_Q_TRANSSZ, -1);
+       setquirk("Firefox",             "Dialog",       ".*",
+           SWM_Q_FLOAT, -1);
+       setquirk("Gimp",                "gimp",         ".*",
+           SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+       setquirk("XTerm",               "xterm",        ".*",
+           SWM_Q_XTERM_FONTADJ, -1);
+       setquirk("xine",                "Xine Window",  ".*",
+           SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+       setquirk("Xitk",                "Xitk Combo",   ".*",
+           SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+       setquirk("xine",                "xine Panel",   ".*",
+           SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+       setquirk("Xitk",                "Xine Window",  ".*",
+           SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+       setquirk("xine",                "xine Video Fullscreen Window", ".*",
+           SWM_Q_FULLSCREEN | SWM_Q_FLOAT, -1);
+       setquirk("pcb",                 "pcb",          ".*",
+           SWM_Q_FLOAT, -1);
+       setquirk("SDL_App",             "SDL_App",      ".*",
+           SWM_Q_FLOAT | SWM_Q_FULLSCREEN, -1);
  }
  
  /* conf file stuff */
@@@ -7870,7 -7907,6 +7937,7 @@@ enum 
        SWM_S_BOUNDARY_WIDTH,
        SWM_S_CLOCK_ENABLED,
        SWM_S_CLOCK_FORMAT,
 +      SWM_S_COMPOSITE_ENABLED,
        SWM_S_CYCLE_EMPTY,
        SWM_S_CYCLE_VISIBLE,
        SWM_S_DIALOG_RATIO,
        SWM_S_FOCUS_MODE,
        SWM_S_ICONIC_ENABLED,
        SWM_S_JAVA_WORKAROUND,
 +      SWM_S_OPACITY_FOCUS,
 +      SWM_S_OPACITY_UNFOCUS,
        SWM_S_REGION_PADDING,
        SWM_S_SPAWN_ORDER,
        SWM_S_SPAWN_TERM,
        SWM_S_STACK_ENABLED,
        SWM_S_TERM_WIDTH,
        SWM_S_TILE_GAP,
+       SWM_S_URGENT_COLLAPSE,
        SWM_S_URGENT_ENABLED,
        SWM_S_VERBOSE_LAYOUT,
+       SWM_S_WARP_POINTER,
        SWM_S_WINDOW_CLASS_ENABLED,
        SWM_S_WINDOW_INSTANCE_ENABLED,
        SWM_S_WINDOW_NAME_ENABLED,
@@@ -8092,26 -8128,12 +8161,29 @@@ setconfvalue(const char *selector, cons
        case SWM_S_TILE_GAP:
                tile_gap = atoi(value);
                break;
+       case SWM_S_URGENT_COLLAPSE:
+               urgent_collapse = (atoi(value) != 0);
+               break;
        case SWM_S_URGENT_ENABLED:
                urgent_enabled = (atoi(value) != 0);
                break;
 +      case SWM_S_COMPOSITE_ENABLED:
 +              composite_enabled = atoi(value);
 +              break;
 +      case SWM_S_OPACITY_FOCUS:
 +              opacity_focus = atof(value);
 +              if (opacity_focus > 1.0)
 +                      opacity_focus = 1.0;
 +              else if (opacity_focus < 0.0)
 +                      opacity_focus = 0.0;
 +              break;
 +      case SWM_S_OPACITY_UNFOCUS:
 +              opacity_unfocus = atof(value);
 +              if (opacity_unfocus > 1.0)
 +                      opacity_unfocus = 1.0;
 +              else if (opacity_unfocus < 0.0)
 +                      opacity_unfocus = 0.0;
 +              break;
        case SWM_S_VERBOSE_LAYOUT:
                verbose_layout = (atoi(value) != 0);
                for (i = 0; layouts[i].l_stack != NULL; i++) {
                                layouts[i].l_string = plain_stacker;
                }
                break;
+       case SWM_S_WARP_POINTER:
+               warp_pointer = (atoi(value) != 0);
+               break;
        case SWM_S_WINDOW_CLASS_ENABLED:
                window_class_enabled = (atoi(value) != 0);
                break;
@@@ -8426,7 -8451,6 +8501,7 @@@ struct config_option configopt[] = 
        { "color_focus_maximized",      setconfcolor,   SWM_S_COLOR_FOCUS_MAXIMIZED },
        { "color_unfocus",              setconfcolor,   SWM_S_COLOR_UNFOCUS },
        { "color_unfocus_maximized",    setconfcolor,   SWM_S_COLOR_UNFOCUS_MAXIMIZED },
 +      { "composite_enabled",          setconfvalue,   SWM_S_COMPOSITE_ENABLED },
        { "cycle_empty",                setconfvalue,   SWM_S_CYCLE_EMPTY },
        { "cycle_visible",              setconfvalue,   SWM_S_CYCLE_VISIBLE },
        { "dialog_ratio",               setconfvalue,   SWM_S_DIALOG_RATIO },
        { "keyboard_mapping",           setkeymapping,  0 },
        { "layout",                     setlayout,      0 },
        { "modkey",                     setconfmodkey,  0 },
 +      { "opacity_focus",              setconfvalue,   SWM_S_OPACITY_FOCUS },
 +      { "opacity_unfocus",            setconfvalue,   SWM_S_OPACITY_UNFOCUS },
        { "program",                    setconfspawn,   0 },
        { "quirk",                      setconfquirk,   0 },
        { "region",                     setconfregion,  0 },
        { "tile_gap",                   setconfvalue,   SWM_S_TILE_GAP },
        { "title_class_enabled",        setconfvalue,   SWM_S_WINDOW_CLASS_ENABLED }, /* For backwards compat. */
        { "title_name_enabled",         setconfvalue,   SWM_S_WINDOW_INSTANCE_ENABLED }, /* For backwards compat. */
+       { "urgent_collapse",            setconfvalue,   SWM_S_URGENT_COLLAPSE },
        { "urgent_enabled",             setconfvalue,   SWM_S_URGENT_ENABLED },
        { "verbose_layout",             setconfvalue,   SWM_S_VERBOSE_LAYOUT },
+       { "warp_pointer",               setconfvalue,   SWM_S_WARP_POINTER },
        { "window_class_enabled",       setconfvalue,   SWM_S_WINDOW_CLASS_ENABLED },
        { "window_instance_enabled",    setconfvalue,   SWM_S_WINDOW_INSTANCE_ENABLED },
        { "window_name_enabled",        setconfvalue,   SWM_S_WINDOW_NAME_ENABLED },
@@@ -8778,7 -8802,7 +8855,7 @@@ manage_window(xcb_window_t id, int spaw
        xcb_get_geometry_reply_t        *gr;
        xcb_window_t            trans = XCB_WINDOW_NONE;
        uint32_t                i, wa[2], new_flags;
-       int                     ws_idx;
+       int                     ws_idx, force_ws = -1;
        char                    *class, *instance, *name;
  
        if ((win = find_window(id)) != NULL) {
        xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL |
            XCB_CW_EVENT_MASK, wa);
  
 +      if (composite_enabled)
 +              set_opacity(win, opacity_unfocus * OPAQUE);
 +
        /* Get WM_SIZE_HINTS. */
        xcb_icccm_get_wm_normal_hints_reply(conn,
            xcb_icccm_get_wm_normal_hints(conn, win->id),
                    regexec(&qp->regex_instance, instance, 0, NULL, 0) == 0 &&
                    regexec(&qp->regex_name, name, 0, NULL, 0) == 0) {
                        DNPRINTF(SWM_D_CLASS, "manage_window: matched "
-                           "quirk: %s:%s:%s mask: %#lx\n", qp->class,
-                           qp->instance, qp->name, qp->quirk);
+                           "quirk: %s:%s:%s mask: %#x, ws: %d\n", qp->class,
+                           qp->instance, qp->name, qp->quirk, qp->ws);
                        win->quirks = qp->quirk;
+                       if (qp->ws >= 0 && qp->ws < workspace_limit)
+                               force_ws = qp->ws;
                }
        }
  
                win->ws = r->ws;
        }
  
+       if (force_ws != -1)
+               win->ws = &r->s->ws[force_ws];
        /* Set the _NET_WM_DESKTOP atom. */
        DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n",
            win->ws->idx);
@@@ -9592,6 -9618,7 +9674,7 @@@ mapnotify(xcb_map_notify_event_t *e
                if (ws->focus_pending == win) {
                        focus_win(win);
                        ws->focus_pending = NULL;
+                       center_pointer(win->ws->r);
                        focus_flush();
                }
        }
@@@ -9854,6 -9881,7 +9937,7 @@@ unmapnotify(xcb_unmap_notify_event_t *e
                }
        }
  
+       center_pointer(ws->r);
        focus_flush();
  }
  
diff --combined spectrwm.conf
@@@ -8,6 -8,7 +8,7 @@@
  # focus_close_wrap    = 1
  # focus_default               = last
  # spawn_position              = next
+ # warp_pointer                = 1
  
  # Window Decoration
  # border_width                = 1
  # Remove window border when bar is disabled and there is only one window in workspace
  # disable_border              = 1
  
 +# Hinting for composite managers such as xcompmgr
 +# composite_enabled   = 1
 +# opacity_focus               = 1.0
 +# opacity_unfocus     = 0.6
 +
  # Bar Settings
  # bar_enabled         = 1
  # bar_border_width    = 1