merge r6227-6246 from trunk
authorDana Jansens <danakj@orodu.net>
Wed, 9 May 2007 23:44:03 +0000 (23:44 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 9 May 2007 23:44:03 +0000 (23:44 +0000)
18 files changed:
COMPLIANCE
openbox/action.c
openbox/client.c
openbox/client.h
openbox/event.c
openbox/frame.c
openbox/frame.h
openbox/menu.c
openbox/modkeys.c
openbox/modkeys.h
openbox/mouse.c
openbox/openbox.c
openbox/prop.c
openbox/prop.h
openbox/screen.c
openbox/session.c
render/font.c
render/theme.c

index ea9247f46a2ffa7995a7074b570ebd2a74e8c6e1..023584669a8705114ab02ae6d000bf53df6847ce 100644 (file)
@@ -46,15 +46,14 @@ the version of the spec which Openbox is compliant up to for the hint.
 + _NET_WM_STRUT (1.3)
 + _NET_WM_STRUT_PARTIAL (1.3)
        Openbox uses these to create per-monitor struts in Xinerama setups.
-- _NET_WM_ICON_GEOMETRY (1.3)
-       Openbox does not display icons for iconic windows.
++ _NET_WM_ICON_GEOMETRY (1.3)
 + _NET_WM_ICON (1.3)
 - _NET_WM_PID (1.3)
-       Openbox does not make use of available PIDs as I don't believe there is
-       a reliable way to tell what client the window is running on.
+       Openbox does not currently kill processes.
 - _NET_WM_HANDLED_ICONS (1.3)
        Openbox does not display icons for iconic windows.
 + _NET_WM_USER_TIME (1.3)
++ _NET_WM_USER_TIME_WINDOW (1.4)
 - _NET_WM_PING (1.3)
        Openbox doesn't look for hung processes at this time.
 + _NET_FRAME_EXTENTS (1.3)
@@ -64,4 +63,4 @@ the version of the spec which Openbox is compliant up to for the hint.
 + _NET_WM_SYNC_REQUEST (1.3)
 + _NET_WM_FULL_PLACEMENT (1.4)
 + _NET_WM_MOVERESIZE_CANCEL (1.4)
-- _NET_REQUEST_FRAME_EXTENTS (1.3)
++ _NET_REQUEST_FRAME_EXTENTS (1.3)
index 24388dca7432314d6a299dfffe40a2abe23daaf7..bcd1b60fd1f05cee66e17e7b6733d38959e11560 100644 (file)
@@ -1589,7 +1589,8 @@ void action_toggle_decorations(union ActionData *data)
     client_action_end(data);
 }
 
-static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
+static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
+                           gboolean shaded)
 {
     /* let's make x and y client relative instead of screen relative */
     x = x - cx;
@@ -1629,11 +1630,11 @@ static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
       |CCCCCCC              |     A           B     |              DDDDDDD|
       |       CCCCCCCC      |     A |       | B     |      DDDDDDDD       |
       |               CCCCCCC      A         B      DDDDDDD               |
-      - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - -
-      |                     |       b       c       |                     |
-      |             west    |       b  move c       |   east              |
-      |                     |       b       c       |                     |
-      - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - 
+      - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
+      |                     |       b       c       |                     | sh
+      |             west    |       b  move c       |   east              | ad
+      |                     |       b       c       |                     | ed
+      - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - -  -
       |               EEEEEEE      G         H      FFFFFFF               |
       |       EEEEEEEE      |     G |       | H     |      FFFFFFFF       |
       |EEEEEEE              |     G           H     |              FFFFFFF|
@@ -1650,6 +1651,15 @@ static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
       +---------------------G-------|-------|-------H---------------------+
     */
 
+    if (shaded) {
+        /* for shaded windows, you can only resize west/east and move */
+        if (b)
+            return prop_atoms.net_wm_moveresize_size_left;
+        if (c)
+            return prop_atoms.net_wm_moveresize_size_right;
+        return prop_atoms.net_wm_moveresize_move;
+    }
+
     if (y < A && y >= C)
         return prop_atoms.net_wm_moveresize_size_topleft;
     else if (y >= A && y >= B && a)
@@ -1705,7 +1715,7 @@ void action_moveresize(union ActionData *data)
                               c->area.width + c->frame->size.left +
                               c->frame->size.right,
                               c->area.height + c->frame->size.top +
-                              c->frame->size.bottom));
+                              c->frame->size.bottom, c->shaded));
     }
 
     moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
index 3f3f161de016c79126136d3eb84491f4d8a09a5a..0c4cce1f50be47e9a6f489790b2cb2b2ef9c6299 100644 (file)
@@ -66,7 +66,7 @@ GList            *client_list          = NULL;
 
 static GSList *client_destructors      = NULL;
 
-static void client_get_all(ObClient *self);
+static void client_get_all(ObClient *self, gboolean real);
 static void client_toggle_border(ObClient *self, gboolean show);
 static void client_get_startup_id(ObClient *self);
 static void client_get_session_ids(ObClient *self);
@@ -76,9 +76,7 @@ static void client_get_state(ObClient *self);
 static void client_get_layer(ObClient *self);
 static void client_get_shaped(ObClient *self);
 static void client_get_mwm_hints(ObClient *self);
-static void client_get_gravity(ObClient *self);
 static void client_get_colormap(ObClient *self);
-static void client_get_transientness(ObClient *self);
 static void client_change_allowed_actions(ObClient *self);
 static void client_change_state(ObClient *self);
 static void client_change_wm_state(ObClient *self);
@@ -236,8 +234,8 @@ void client_manage(Window window)
 
     grab_server(TRUE);
 
-    /* check if it has already been unmapped by the time we started mapping.
-       the grab does a sync so we don't have to here */
+    /* check if it has already been unmapped by the time we started
+       mapping. the grab does a sync so we don't have to here */
     if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
         XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
     {
@@ -277,7 +275,6 @@ void client_manage(Window window)
     XChangeWindowAttributes(ob_display, window,
                             CWEventMask|CWDontPropagate, &attrib_set);
 
-
     /* create the ObClient struct, and populate it from the hints on the
        window */
     self = g_new0(ObClient, 1);
@@ -290,7 +287,7 @@ void client_manage(Window window)
     self->desktop = screen_num_desktops; /* always an invalid value */
     self->user_time = focus_client ? focus_client->user_time : CurrentTime;
 
-    client_get_all(self);
+    client_get_all(self, TRUE);
     /* per-app settings override stuff, and return the settings for other
        uses too */
     settings = client_get_settings_state(self);
@@ -311,14 +308,14 @@ void client_manage(Window window)
     /* remove the client's border (and adjust re gravity) */
     client_toggle_border(self, FALSE);
      
-    /* specify that if we exit, the window should not be destroyed and should
-       be reparented back to root automatically */
+    /* specify that if we exit, the window should not be destroyed and
+       should be reparented back to root automatically */
     XChangeSaveSet(ob_display, window, SetModeInsert);
 
     /* create the decoration frame for the client window */
     self->frame = frame_new(self);
 
-    frame_grab_client(self->frame, self);
+    frame_grab_client(self->frame);
 
     /* do this after we have a frame.. it uses the frame to help determine the
        WM_STATE to apply. */
@@ -484,6 +481,31 @@ void client_manage(Window window)
     client_set_list();
 
     ob_debug("Managed window 0x%lx (%s)\n", window, self->class);
+
+    return;
+}
+
+
+ObClient *client_fake_manage(Window window)
+{
+    ObClient *self;
+    ObAppSettings *settings;
+
+    ob_debug("Pretend-managing window: %lx\n", window);
+
+    /* do this minimal stuff to figure out the client's decorations */
+
+    self = g_new0(ObClient, 1);
+    self->window = window;
+
+    client_get_all(self, FALSE);
+    /* per-app settings override stuff, and return the settings for other
+       uses too */
+    settings = client_get_settings_state(self);
+
+    /* create the decoration frame for the client window */
+    self->frame = frame_new(self);
+    return self;
 }
 
 void client_unmanage_all()
@@ -497,8 +519,8 @@ void client_unmanage(ObClient *self)
     guint j;
     GSList *it;
 
-    ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class,
-             self->title ? self->title : "");
+    ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window,
+             self->class, self->title ? self->title : "");
 
     g_assert(self != NULL);
 
@@ -510,7 +532,8 @@ void client_unmanage(ObClient *self)
     /* flush to send the hide to the server quickly */
     XFlush(ob_display);
 
-    /* ignore enter events from the unmap so it doesnt mess with the focus */
+    /* ignore enter events from the unmap so it doesnt mess with the
+       focus */
     event_ignore_queued_enters();
 
     mouse_grab_for_client(self, FALSE);
@@ -547,7 +570,7 @@ void client_unmanage(ObClient *self)
         for (it = self->group->members; it; it = g_slist_next(it))
             if (it->data != self)
                 ((ObClient*)it->data)->transients =
-                    g_slist_remove(((ObClient*)it->data)->transients, self);
+                    g_slist_remove(((ObClient*)it->data)->transients,self);
     } else if (self->transient_for) {        /* transient of window */
         self->transient_for->transients =
             g_slist_remove(self->transient_for->transients, self);
@@ -594,7 +617,8 @@ void client_unmanage(ObClient *self)
     }
 
     /* reparent the window out of the frame, and free the frame */
-    frame_release_client(self->frame, self);
+    frame_release_client(self->frame);
+    frame_free(self->frame);
     self->frame = NULL;
 
     if (ob_state() != OB_STATE_EXITING) {
@@ -604,11 +628,15 @@ void client_unmanage(ObClient *self)
         PROP_ERASE(self->window, net_wm_state);
         PROP_ERASE(self->window, wm_state);
     } else {
-        /* if we're left in an unmapped state, the client wont be mapped. this
-           is bad, since we will no longer be managing the window on restart */
+        /* if we're left in an unmapped state, the client wont be mapped.
+           this is bad, since we will no longer be managing the window on
+           restart */
         XMapWindow(ob_display, self->window);
     }
 
+    /* update the list hints */
+    client_set_list();
+
     ob_debug("Unmanaged window 0x%lx\n", self->window);
 
     /* free all data allocated in the client struct */
@@ -626,9 +654,14 @@ void client_unmanage(ObClient *self)
     g_free(self->client_machine);
     g_free(self->sm_client_id);
     g_free(self);
-     
-    /* update the list hints */
-    client_set_list();
+}
+
+void client_fake_unmanage(ObClient *self)
+{
+    /* this is all that got allocated to get the decorations */
+
+    frame_free(self->frame);
+    g_free(self);
 }
 
 static ObAppSettings *client_get_settings_state(ObClient *self)
@@ -949,68 +982,62 @@ static void client_toggle_border(ObClient *self, gboolean show)
 }
 
 
-static void client_get_all(ObClient *self)
+static void client_get_all(ObClient *self, gboolean real)
 {
+    /* this is needed for the frame to set itself up */
     client_get_area(self);
-    client_get_mwm_hints(self);
-
-    /* The transient-ness of a window is used to pick a type, but the type can
-       also affect transiency.
 
-       Dialogs are always made transients for their group if they have one.
+    /* these things can change the decor and functions of the window */
 
-       I also have made non-application type windows be transients for their
-       group (eg utility windows).
-    */
-    client_get_transientness(self);
-    client_get_type(self);/* this can change the mwmhints for special cases */
+    client_get_mwm_hints(self);
+    /* this can change the mwmhints for special cases */
+    client_get_type_and_transientness(self);
     client_get_state(self);
+    client_update_protocols(self);
+    client_update_normal_hints(self);
 
-    client_update_wmhints(self);
-    /* this may have already been called from client_update_wmhints */
-    if (self->transient_for == NULL)
-        client_update_transient_for(self);
-    client_get_startup_id(self);
-    client_get_desktop(self);/* uses transient data/group/startup id if a
-                                desktop is not specified */
-    client_get_shaped(self);
-
-    client_get_layer(self); /* if layer hasn't been specified, get it from
-                               other sources if possible */
+    /* got the type, the mwmhints, the protocols, and the normal hints
+       (min/max sizes), so we're ready to set up the decorations/functions */
+    client_setup_decor_and_functions(self);
 
-    {
-        /* a couple type-based defaults for new windows */
+    if (real) {
+        client_update_wmhints(self);
+        /* this may have already been called from client_update_wmhints */
+        if (self->transient_for == NULL)
+            client_update_transient_for(self);
 
-        /* this makes sure that these windows appear on all desktops */
-        if (self->type == OB_CLIENT_TYPE_DESKTOP)
-            self->desktop = DESKTOP_ALL;
-    }
+        client_get_startup_id(self);
+        client_get_desktop(self);/* uses transient data/group/startup id if a
+                                    desktop is not specified */
+        client_get_shaped(self);
 
-    client_update_protocols(self);
+        client_get_layer(self); /* if layer hasn't been specified, get it from
+                                   other sources if possible */
 
-    client_get_gravity(self); /* get the attribute gravity */
-    client_update_normal_hints(self); /* this may override the attribute
-                                         gravity */
+        {
+            /* a couple type-based defaults for new windows */
 
-    /* got the type, the mwmhints, the protocols, and the normal hints
-       (min/max sizes), so we're ready to set up the decorations/functions */
-    client_setup_decor_and_functions(self);
+            /* this makes sure that these windows appear on all desktops */
+            if (self->type == OB_CLIENT_TYPE_DESKTOP)
+                self->desktop = DESKTOP_ALL;
+        }
   
 #ifdef SYNC
-    client_update_sync_request_counter(self);
+        client_update_sync_request_counter(self);
 #endif
 
-    /* get the session related properties */
-    client_get_session_ids(self);
+        /* get the session related properties */
+        client_get_session_ids(self);
 
-    client_get_colormap(self);
-    client_update_title(self);
-    client_update_strut(self);
-    client_update_icons(self);
-    client_update_user_time_window(self);
-    if (!self->user_time_window) /* check if this would have been called */
-        client_update_user_time(self);
-    client_update_icon_geometry(self);
+        client_get_colormap(self);
+        client_update_title(self);
+        client_update_strut(self);
+        client_update_icons(self);
+        client_update_user_time_window(self);
+        if (!self->user_time_window) /* check if this would have been called */
+            client_update_user_time(self);
+        client_update_icon_geometry(self);
+    }
 }
 
 static void client_get_startup_id(ObClient *self)
@@ -1170,20 +1197,12 @@ static void client_get_shaped(ObClient *self)
 #endif
 }
 
-void client_get_transientness(ObClient *self)
-{
-    Window t;
-    if (XGetTransientForHint(ob_display, self->window, &t))
-        self->transient = TRUE;
-}
-
 void client_update_transient_for(ObClient *self)
 {
     Window t = None;
     ObClient *target = NULL;
 
     if (XGetTransientForHint(ob_display, self->window, &t)) {
-        self->transient = TRUE;
         if (t != self->window) { /* cant be transient to itself! */
             target = g_hash_table_lookup(window_map, &t);
             /* if this happens then we need to check for it*/
@@ -1220,16 +1239,8 @@ void client_update_transient_for(ObClient *self)
                 }
             }
         }
-    } else if (self->type == OB_CLIENT_TYPE_DIALOG ||
-               self->type == OB_CLIENT_TYPE_TOOLBAR ||
-               self->type == OB_CLIENT_TYPE_MENU ||
-               self->type == OB_CLIENT_TYPE_UTILITY)
-    {
-        self->transient = TRUE;
-        if (self->group)
-            target = OB_TRAN_GROUP;
-    } else
-        self->transient = FALSE;
+    } else if (self->transient && self->group)
+        target = OB_TRAN_GROUP;
 
     client_update_transient_tree(self, self->group, self->group,
                                  self->transient_for, target);
@@ -1364,12 +1375,14 @@ static void client_get_mwm_hints(ObClient *self)
     }
 }
 
-void client_get_type(ObClient *self)
+void client_get_type_and_transientness(ObClient *self)
 {
     guint num, i;
     guint32 *val;
+    Window t;
 
     self->type = -1;
+    self->transient = FALSE;
   
     if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
         /* use the first value that we know about in the array */
@@ -1403,7 +1416,10 @@ void client_get_type(ObClient *self)
         }
         g_free(val);
     }
-    
+
+    if (XGetTransientForHint(ob_display, self->window, &t))
+        self->transient = TRUE;
+            
     if (self->type == (ObClientType) -1) {
         /*the window type hint was not set, which means we either classify
           ourself as a normal window or a dialog, depending on if we are a
@@ -1413,6 +1429,15 @@ void client_get_type(ObClient *self)
         else
             self->type = OB_CLIENT_TYPE_NORMAL;
     }
+
+    /* then, based on our type, we can update our transientness.. */
+    if (self->type == OB_CLIENT_TYPE_DIALOG ||
+        self->type == OB_CLIENT_TYPE_TOOLBAR ||
+        self->type == OB_CLIENT_TYPE_MENU ||
+        self->type == OB_CLIENT_TYPE_UTILITY)
+    {
+        self->transient = TRUE;
+    }
 }
 
 void client_update_protocols(ObClient *self)
@@ -1456,16 +1481,6 @@ void client_update_sync_request_counter(ObClient *self)
 }
 #endif
 
-static void client_get_gravity(ObClient *self)
-{
-    XWindowAttributes wattrib;
-    Status ret;
-
-    ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
-    g_assert(ret != BadWindow);
-    self->gravity = wattrib.win_gravity;
-}
-
 void client_get_colormap(ObClient *self)
 {
     XWindowAttributes wa;
@@ -1649,7 +1664,7 @@ void client_setup_decor_and_functions(ObClient *self)
 
     /* kill the handle on fully maxed windows */
     if (self->max_vert && self->max_horz)
-        self->decorations &= ~OB_FRAME_DECOR_HANDLE;
+        self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS);
 
     /* finally, the user can have requested no decorations, which overrides
        everything (but doesnt give it a border if it doesnt have one) */
@@ -2184,6 +2199,8 @@ static void client_get_session_ids(ObClient *self)
         localhost[127] = '\0';
         if (strcmp(localhost, s) != 0)
             self->client_machine = s;
+        else
+            g_free(s);
     }
 }
 
index f9a194831a3b4da8666d81d83960ff3f4da0aff5..30d40510f509cf83057a6197f2ebadc3009294fa 100644 (file)
@@ -314,13 +314,22 @@ void client_remove_destructor(ObClientCallback func);
 
 /*! Manages all existing windows */
 void client_manage_all();
-/*! Manages a given window */
+/*! Manages a given window
+*/
 void client_manage(Window win);
 /*! Unmanages all managed windows */
 void client_unmanage_all();
 /*! Unmanages a given client */
 void client_unmanage(ObClient *client);
 
+/*! This manages a window only so far as is needed to get it's decorations.
+   This is used when you want to determine a window's decorations before it
+   is mapped. Call client_fake_unmanage() with the returned client when you
+   are done with it. */
+ObClient *client_fake_manage(Window win);
+/*! Free the stuff created by client_fake_manage() */
+void client_fake_unmanage(ObClient *self);
+
 /*! Sets the client list on the root window from the client_list */
 void client_set_list();
 
@@ -354,7 +363,7 @@ gboolean client_focused(ObClient *self);
 
 /*! Convery a position/size from a given gravity to the client's true gravity
  */
-void client_convert_gravity(ObClient *client, gint gravity, gint *x, gint *y,
+void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y,
                             gint w, gint h);
 
 #define client_move(self, x, y) \
@@ -536,7 +545,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user);
 
 /*! Bring all of its helper windows to its desktop. These are the utility and
   stuff windows. */
-void client_bring_helper_windows(ObClient *client);
+void client_bring_helper_windows(ObClient *self);
 
 /*! Calculates the stacking layer for the client window */
 void client_calc_layer(ObClient *self);
@@ -600,8 +609,8 @@ void client_update_icon_geometry(ObClient *self);
 */
 void client_setup_decor_and_functions(ObClient *self);
 
-/*! Retrieves the window's type and sets ObClient->type */
-void client_get_type(ObClient *self);
+/*! Sets the window's type and transient flag */
+void client_get_type_and_transientness(ObClient *self);
 
 const ObClientIcon *client_icon(ObClient *self, gint w, gint h);
 
index babb5197c193ee0316f7403ad303dc2d107b2683..8523f637448db9e9dc18686579d0064b368a2be2 100644 (file)
@@ -568,8 +568,32 @@ static void event_process(const XEvent *ec, gpointer data)
         event_handle_root(e);
     else if (e->type == MapRequest)
         client_manage(window);
+    else if (e->type == ClientMessage) {
+        /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
+           windows that are not managed yet. */
+        if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
+            /* Pretend to manage the client, getting information used to
+               determine its decorations */
+            ObClient *c = client_fake_manage(e->xclient.window);
+            gulong vals[4];
+
+            /* adjust the decorations so we know the sizes */
+            frame_adjust_area(c->frame, FALSE, TRUE, TRUE);
+
+            /* set the frame extents on the window */
+            vals[0] = c->frame->size.left;
+            vals[1] = c->frame->size.right;
+            vals[2] = c->frame->size.top;
+            vals[3] = c->frame->size.bottom;
+            PROP_SETA32(e->xclient.window, net_frame_extents,
+                        cardinal, vals, 4);
+
+            /* Free the pretend client */
+            client_fake_unmanage(c);
+        }
+    }
     else if (e->type == ConfigureRequest) {
-        /* unhandled configure requests must be used to configure the
+        /* unhandled config5Aure requests must be used to configure the
            window directly */
         XWindowChanges xwc;
 
@@ -705,9 +729,17 @@ static void event_handle_client(ObClient *client, XEvent *e)
     XEvent ce;
     Atom msgtype;
     ObFrameContext con;
+    static gint px = -1, py = -1;
+    static guint pb = 0;
      
     switch (e->type) {
     case ButtonPress:
+        /* save where the press occured for the first button pressed */
+        if (!pb) {
+            pb = e->xbutton.button;
+            px = e->xbutton.x;
+            py = e->xbutton.y;
+        }
     case ButtonRelease:
         /* Wheel buttons don't draw because they are an instant click, so it
            is a waste of resources to go drawing it.
@@ -719,8 +751,13 @@ static void event_handle_client(ObClient *client, XEvent *e)
             !keyboard_interactively_grabbed() &&
             !menu_frame_visible)
         {
-            con = frame_context(client, e->xbutton.window);
+            /* use where the press occured */
+            con = frame_context(client, e->xbutton.window, px, py);
             con = mouse_button_frame_context(con, e->xbutton.button);
+
+            if (e->type == ButtonRelease && e->xbutton.button == pb)
+                pb = 0, px = py = -1;
+
             switch (con) {
             case OB_FRAME_CONTEXT_MAXIMIZE:
                 client->frame->max_press = (e->type == ButtonPress);
@@ -748,8 +785,46 @@ static void event_handle_client(ObClient *client, XEvent *e)
             }
         }
         break;
+    case MotionNotify:
+        con = frame_context(client, e->xmotion.window,
+                            e->xmotion.x, e->xmotion.y);
+        switch (con) {
+        case OB_FRAME_CONTEXT_TITLEBAR:
+            /* we've left the button area inside the titlebar */
+            client->frame->max_hover = FALSE;
+            client->frame->desk_hover = FALSE;
+            client->frame->shade_hover = FALSE;
+            client->frame->iconify_hover = FALSE;
+            client->frame->close_hover = FALSE;
+            frame_adjust_state(client->frame);
+            break;
+        case OB_FRAME_CONTEXT_MAXIMIZE:
+            client->frame->max_hover = TRUE;
+            frame_adjust_state(client->frame);
+            break;
+        case OB_FRAME_CONTEXT_ALLDESKTOPS:
+            client->frame->desk_hover = TRUE;
+            frame_adjust_state(client->frame);
+            break;
+        case OB_FRAME_CONTEXT_SHADE:
+            client->frame->shade_hover = TRUE;
+            frame_adjust_state(client->frame);
+            break;
+        case OB_FRAME_CONTEXT_ICONIFY:
+            client->frame->iconify_hover = TRUE;
+            frame_adjust_state(client->frame);
+            break;
+        case OB_FRAME_CONTEXT_CLOSE:
+            client->frame->close_hover = TRUE;
+            frame_adjust_state(client->frame);
+            break;
+        default:
+            break;
+        }
+        break;
     case LeaveNotify:
-        con = frame_context(client, e->xcrossing.window);
+        con = frame_context(client, e->xcrossing.window,
+                            e->xcrossing.x, e->xcrossing.y);
         switch (con) {
         case OB_FRAME_CONTEXT_MAXIMIZE:
             client->frame->max_hover = FALSE;
@@ -809,7 +884,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
             nofocus = TRUE;
         }
 
-        con = frame_context(client, e->xcrossing.window);
+        con = frame_context(client, e->xcrossing.window,
+                            e->xcrossing.x, e->xcrossing.y);
         switch (con) {
         case OB_FRAME_CONTEXT_MAXIMIZE:
             client->frame->max_hover = TRUE;
@@ -1167,7 +1243,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_update_wmhints(client);
         } else if (msgtype == XA_WM_TRANSIENT_FOR) {
             client_update_transient_for(client);
-            client_get_type(client);
+            client_get_type_and_transientness(client);
             /* type may have changed, so update the layer */
             client_calc_layer(client);
             client_setup_decor_and_functions(client);
index 2c3fb58fc4af040d57fc97e465b212928ceef405..1f45ea8b145217d7d72beaf8c8232dde8e0c1325 100644 (file)
@@ -34,7 +34,7 @@
 #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
                          ButtonPressMask | ButtonReleaseMask)
 #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
-                           ButtonMotionMask | \
+                           ButtonMotionMask | PointerMotionMask | \
                            EnterWindowMask | LeaveWindowMask)
 /* The inner window does not need enter/leave events.
    If it does get them, then it needs its own context for enter events
@@ -99,6 +99,7 @@ ObFrame *frame_new(ObClient *client)
     Visual *visual;
 
     self = g_new0(ObFrame, 1);
+    self->client = client;
 
     visual = check_32bit_client(client);
 
@@ -245,7 +246,7 @@ static void free_theme_statics(ObFrame *self)
     RrAppearanceFree(self->a_icon);
 }
 
-static void frame_free(ObFrame *self)
+void frame_free(ObFrame *self)
 {
     free_theme_statics(self);
 
@@ -553,12 +554,10 @@ void frame_adjust_icon(ObFrame *self)
     framerender_frame(self);
 }
 
-void frame_grab_client(ObFrame *self, ObClient *client)
+void frame_grab_client(ObFrame *self)
 {
-    self->client = client;
-
     /* reparent the client to the frame */
-    XReparentWindow(ob_display, client->window, self->plate, 0, 0);
+    XReparentWindow(ob_display, self->client->window, self->plate, 0, 0);
     /*
       When reparenting the client window, it is usually not mapped yet, since
       this occurs from a MapRequest. However, in the case where Openbox is
@@ -568,52 +567,50 @@ void frame_grab_client(ObFrame *self, ObClient *client)
       handled and need to be ignored.
     */
     if (ob_state() == OB_STATE_STARTING)
-        client->ignore_unmaps += 2;
+        self->client->ignore_unmaps += 2;
 
     /* select the event mask on the client's parent (to receive config/map
        req's) the ButtonPress is to catch clicks on the client border */
     XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
 
     /* map the client so it maps when the frame does */
-    XMapWindow(ob_display, client->window);
+    XMapWindow(ob_display, self->client->window);
 
     /* adjust the frame to the client's size */
     frame_adjust_area(self, FALSE, TRUE, FALSE);
 
     /* set all the windows for the frame in the window_map */
-    g_hash_table_insert(window_map, &self->window, client);
-    g_hash_table_insert(window_map, &self->plate, client);
-    g_hash_table_insert(window_map, &self->inner, client);
-    g_hash_table_insert(window_map, &self->title, client);
-    g_hash_table_insert(window_map, &self->label, client);
-    g_hash_table_insert(window_map, &self->max, client);
-    g_hash_table_insert(window_map, &self->close, client);
-    g_hash_table_insert(window_map, &self->desk, client);
-    g_hash_table_insert(window_map, &self->shade, client);
-    g_hash_table_insert(window_map, &self->icon, client);
-    g_hash_table_insert(window_map, &self->iconify, client);
-    g_hash_table_insert(window_map, &self->handle, client);
-    g_hash_table_insert(window_map, &self->lgrip, client);
-    g_hash_table_insert(window_map, &self->rgrip, client);
-    g_hash_table_insert(window_map, &self->tltresize, client);
-    g_hash_table_insert(window_map, &self->tllresize, client);
-    g_hash_table_insert(window_map, &self->trtresize, client);
-    g_hash_table_insert(window_map, &self->trrresize, client);
+    g_hash_table_insert(window_map, &self->window, self->client);
+    g_hash_table_insert(window_map, &self->plate, self->client);
+    g_hash_table_insert(window_map, &self->inner, self->client);
+    g_hash_table_insert(window_map, &self->title, self->client);
+    g_hash_table_insert(window_map, &self->label, self->client);
+    g_hash_table_insert(window_map, &self->max, self->client);
+    g_hash_table_insert(window_map, &self->close, self->client);
+    g_hash_table_insert(window_map, &self->desk, self->client);
+    g_hash_table_insert(window_map, &self->shade, self->client);
+    g_hash_table_insert(window_map, &self->icon, self->client);
+    g_hash_table_insert(window_map, &self->iconify, self->client);
+    g_hash_table_insert(window_map, &self->handle, self->client);
+    g_hash_table_insert(window_map, &self->lgrip, self->client);
+    g_hash_table_insert(window_map, &self->rgrip, self->client);
+    g_hash_table_insert(window_map, &self->tltresize, self->client);
+    g_hash_table_insert(window_map, &self->tllresize, self->client);
+    g_hash_table_insert(window_map, &self->trtresize, self->client);
+    g_hash_table_insert(window_map, &self->trrresize, self->client);
 }
 
-void frame_release_client(ObFrame *self, ObClient *client)
+void frame_release_client(ObFrame *self)
 {
     XEvent ev;
     gboolean reparent = TRUE;
 
-    g_assert(self->client == client);
-
     /* if there was any animation going on, kill it */
     ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
                                      self, FALSE);
 
     /* check if the app has already reparented its window away */
-    while (XCheckTypedWindowEvent(ob_display, client->window,
+    while (XCheckTypedWindowEvent(ob_display, self->client->window,
                                   ReparentNotify, &ev))
     {
         /* This check makes sure we don't catch our own reparent action to
@@ -633,10 +630,10 @@ void frame_release_client(ObFrame *self, ObClient *client)
     if (reparent) {
         /* according to the ICCCM - if the client doesn't reparent itself,
            then we will reparent the window to root for them */
-        XReparentWindow(ob_display, client->window,
+        XReparentWindow(ob_display, self->client->window,
                         RootWindow(ob_display, ob_screen),
-                        client->area.x,
-                        client->area.y);
+                        self->client->area.x,
+                        self->client->area.y);
     }
 
     /* remove all the windows for the frame from the window_map */
@@ -660,8 +657,6 @@ void frame_release_client(ObFrame *self, ObClient *client)
     g_hash_table_remove(window_map, &self->trrresize);
 
     ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
-
-    frame_free(self);
 }
 
 /* is there anything present between us and the label? */
@@ -688,7 +683,7 @@ static gboolean is_button_present(ObFrame *self, const gchar *lc, gint dir) {
 static void layout_title(ObFrame *self)
 {
     gchar *lc;
-    gint i, x;
+    gint i;
 
     const gint bwidth = ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
     /* position of the left most button */
@@ -700,6 +695,7 @@ static void layout_title(ObFrame *self)
     self->icon_on = self->desk_on = self->shade_on = self->iconify_on =
         self->max_on = self->close_on = self->label_on = FALSE;
     self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
+    self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
 
     /* figure out what's being show, find each element's position, and the
        width of the label
@@ -708,16 +704,21 @@ static void layout_title(ObFrame *self)
        i will be +1 the first time through when working to the left,
        and -1 the second time through when working to the right */
     for (i = 1; i >= -1; i-=2) {
+        gint x;
+        ObFrameContext *firstcon;
+
         if (i > 0) {
             x = left;
             lc = config_title_layout;
+            firstcon = &self->leftmost;
         } else {
             x = right;
             lc = config_title_layout + strlen(config_title_layout)-1;
+            firstcon = &self->rightmost;
         }
 
         /* stop at the end of the string (or the label, which calls break) */
-        for (; *lc != '\0' && lc >= config_title_layout; lc+=i)
+        for (; *lc != '\0' && lc >= config_title_layout; lc+=i) {
             if (*lc == 'L') {
                 if (i > 0) {
                     self->label_on = TRUE;
@@ -725,6 +726,7 @@ static void layout_title(ObFrame *self)
                 }
                 break; /* break the for loop, do other side of label */
             } else if (*lc == 'N') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICON;
                 if ((self->icon_on = is_button_present(self, lc, i))) {
                     /* icon gets extra padding */
                     self->label_width -= bwidth + 2;
@@ -732,36 +734,44 @@ static void layout_title(ObFrame *self)
                     x += i * (bwidth + 2);
                 }
             } else if (*lc == 'D') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
                 if ((self->desk_on = is_button_present(self, lc, i))) {
                     self->label_width -= bwidth;
                     self->desk_x = x;
                     x += i * bwidth;
                 }
             } else if (*lc == 'S') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_SHADE;
                 if ((self->shade_on = is_button_present(self, lc, i))) {
                     self->label_width -= bwidth;
                     self->shade_x = x;
                     x += i * bwidth;
                 }
             } else if (*lc == 'I') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICONIFY;
                 if ((self->iconify_on = is_button_present(self, lc, i))) {
                     self->label_width -= bwidth;
                     self->iconify_x = x;
                     x += i * bwidth;
                 }
             } else if (*lc == 'M') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
                 if ((self->max_on = is_button_present(self, lc, i))) {
                     self->label_width -= bwidth;
                     self->max_x = x;
                     x += i * bwidth;
                 }
             } else if (*lc == 'C') {
+                if (firstcon) *firstcon = OB_FRAME_CONTEXT_CLOSE;
                 if ((self->close_on = is_button_present(self, lc, i))) {
                     self->label_width -= bwidth;
                     self->close_x = x;
                     x += i * bwidth;
                 }
-            }
+            } else
+                continue; /* don't set firstcon */
+            firstcon = NULL;
+        }
     }
 
     /* position and map the elements */
@@ -853,7 +863,7 @@ ObFrameContext frame_context_from_string(const gchar *name)
     return OB_FRAME_CONTEXT_NONE;
 }
 
-ObFrameContext frame_context(ObClient *client, Window win)
+ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y)
 {
     ObFrame *self;
 
@@ -880,8 +890,30 @@ ObFrameContext frame_context(ObClient *client, Window win)
         return OB_FRAME_CONTEXT_CLIENT;
     }
 
+    if (win == self->title) {
+        /* when the user clicks in the corners of the titlebar and the client
+           is fully maximized, then treat it like they clicked in the
+           button that is there */
+        if (self->client->max_horz && self->client->max_vert &&
+            y < ob_rr_theme->paddingy + 1 + ob_rr_theme->button_size)
+        {
+            if (x < ((ob_rr_theme->paddingx + 1) * 2 +
+                     ob_rr_theme->button_size)) {
+                if (self->leftmost != OB_FRAME_CONTEXT_NONE)
+                    return self->leftmost;
+            }
+            else if (x > (self->width -
+                          (ob_rr_theme->paddingx + 1 +
+                           ob_rr_theme->button_size)))
+            {
+                if (self->rightmost != OB_FRAME_CONTEXT_NONE)
+                    return self->rightmost;
+            }
+        }
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    }
+
     if (win == self->window)    return OB_FRAME_CONTEXT_FRAME;
-    if (win == self->title)     return OB_FRAME_CONTEXT_TITLEBAR;
     if (win == self->label)     return OB_FRAME_CONTEXT_TITLEBAR;
     if (win == self->handle)    return OB_FRAME_CONTEXT_HANDLE;
     if (win == self->lgrip)     return OB_FRAME_CONTEXT_BLCORNER;
index 3a5dfdb25642895d15f01c5bb53f759a5f2986dd..ebd8de982457afb76cf27b2f846ae9a4c450eae2 100644 (file)
@@ -136,6 +136,10 @@ struct _ObFrame
     gint      cbwidth_x;     /* client border width */
     gint      cbwidth_y;     /* client border width */
 
+    /* the leftmost and rightmost elements in the titlebar */
+    ObFrameContext leftmost;
+    ObFrameContext rightmost;
+
     gboolean  max_press;
     gboolean  close_press;
     gboolean  desk_press;
@@ -162,6 +166,8 @@ struct _ObFrame
 };
 
 ObFrame *frame_new(struct _ObClient *c);
+void frame_free(ObFrame *self);
+
 void frame_show(ObFrame *self);
 void frame_hide(ObFrame *self);
 void frame_adjust_theme(ObFrame *self);
@@ -173,12 +179,13 @@ void frame_adjust_state(ObFrame *self);
 void frame_adjust_focus(ObFrame *self, gboolean hilite);
 void frame_adjust_title(ObFrame *self);
 void frame_adjust_icon(ObFrame *self);
-void frame_grab_client(ObFrame *self, struct _ObClient *client);
-void frame_release_client(ObFrame *self, struct _ObClient *client);
+void frame_grab_client(ObFrame *self);
+void frame_release_client(ObFrame *self);
 
 ObFrameContext frame_context_from_string(const gchar *name);
 
-ObFrameContext frame_context(struct _ObClient *self, Window win);
+ObFrameContext frame_context(struct _ObClient *self, Window win,
+                             gint x, gint y);
 
 /*! Applies gravity to the client's position to find where the frame should
   be positioned.
index 0e203739bda36ca15c2e9c0eae7c9075ad67f6b4..c6e986b970af1f97f5f65ed8e4bd167370fc5b2d 100644 (file)
@@ -357,6 +357,7 @@ static void menu_destroy_hash_value(ObMenu *self)
     g_free(self->name);
     g_free(self->title);
     g_free(self->execute);
+    g_free(self->more_menu);
 
     g_free(self);
 }
index 4eb836e5114548527f2c7bb3a4c71a88ef1031cd..3346a88dccd2f78f021e829d9c90526cf7aeb605 100644 (file)
 static void set_modkey_mask(guchar mask, KeySym sym);
 
 static XModifierKeymap *modmap;
+static KeySym *keymap;
+static gint min_keycode, max_keycode, keysyms_per_keycode;
 /* This is a bitmask of the different masks for each modifier key */
 static guchar modkeys_keys[OB_MODKEY_NUM_KEYS];
 
 void modkeys_startup(gboolean reconfigure)
 {
-    KeySym *keymap;
     gint i, j, k;
-    gint min_keycode, max_keycode, keysyms_per_keycode;
 
     /* reset the keys to not be bound to any masks */
     for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i)
@@ -64,22 +64,25 @@ void modkeys_startup(gboolean reconfigure)
             KeySym sym;
             /* get a keycode that is bound to the mask (i) */
             KeyCode keycode = modmap->modifiermap[i*modmap->max_keypermod + j];
-            /* go through each keysym bound to the given keycode */
-            for (k = 0; k < keysyms_per_keycode; ++k) {
-                sym = keymap[(keycode-min_keycode) * keysyms_per_keycode + k];
-                if (sym != NoSymbol) {
-                    /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */
-                    set_modkey_mask(nth_mask(i), sym);
+            if (keycode) {
+                /* go through each keysym bound to the given keycode */
+                for (k = 0; k < keysyms_per_keycode; ++k) {
+                    sym = keymap[(keycode-min_keycode) * keysyms_per_keycode +
+                                 k];
+                    if (sym != NoSymbol) {
+                        /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */
+                        set_modkey_mask(nth_mask(i), sym);
+                    }
                 }
             }
         }
     }
-    XFree(keymap);
 }
 
 void modkeys_shutdown(gboolean reconfigure)
 {
     XFreeModifiermap(modmap);
+    XFree(keymap);
 }
 
 guint modkeys_keycode_to_mask(guint keycode)
@@ -139,3 +142,16 @@ static void set_modkey_mask(guchar mask, KeySym sym)
     else if (sym == XK_Meta_L || sym == XK_Meta_R)
         modkeys_keys[OB_MODKEY_KEY_META] |= mask;
 }
+
+KeyCode modkeys_sym_to_code(KeySym sym)
+{
+    gint i, j;
+
+    /* go through each keycode and look for the keysym */
+    for (i = min_keycode; i <= max_keycode; ++i)
+        for (j = 0; j < keysyms_per_keycode; ++j)
+            if (sym == keymap[(i-min_keycode) * keysyms_per_keycode + j])
+                return i;
+    return 0;
+}
+
index cfa95b045f667e6eefa00ab536c2b09fdde9c8ef..8f2223697d2845ed7dbb1e23d2546b85edbab60c 100644 (file)
@@ -20,6 +20,7 @@
 #define ob__modkeys_h
 
 #include <glib.h>
+#include <X11/Xlib.h>
 
 /*! These keys are bound to the modifier masks in any fashion */
 typedef enum {
@@ -51,4 +52,8 @@ guint modkeys_only_modifier_masks(guint mask);
   right keys when there are both. */
 guint modkeys_key_to_mask(ObModkeysKey key);
 
+/*! Convert a KeySym to a KeyCode, because the X function is terrible - says
+  valgrind. */
+KeyCode modkeys_sym_to_code(KeySym sym);
+
 #endif
index 522eba8cbf9c8ccb27b241ae330c8ad4ab6c4083..9edda8ebf96aa05e7469ebe203feb6ac2f7cd2af 100644 (file)
@@ -179,7 +179,7 @@ void mouse_event(ObClient *client, XEvent *e)
     static Time ltime;
     static guint button = 0, state = 0, lbutton = 0;
     static Window lwindow = None;
-    static gint px, py;
+    static gint px, py, pwx = -1, pwy = -1;
 
     ObFrameContext context;
     gboolean click = FALSE;
@@ -187,11 +187,14 @@ void mouse_event(ObClient *client, XEvent *e)
 
     switch (e->type) {
     case ButtonPress:
-        context = frame_context(client, e->xany.window);
+        context = frame_context(client, e->xbutton.window,
+                                e->xbutton.x, e->xbutton.y);
         context = mouse_button_frame_context(context, e->xbutton.button);
 
         px = e->xbutton.x_root;
         py = e->xbutton.y_root;
+        if (pwx == -1) pwx = e->xbutton.x;
+        if (pwy == -1) pwy = e->xbutton.y;
         button = e->xbutton.button;
         state = e->xbutton.state;
 
@@ -209,9 +212,12 @@ void mouse_event(ObClient *client, XEvent *e)
             break;
 
     case ButtonRelease:
-        context = frame_context(client, e->xany.window);
+        /* use where the press occured in the window */
+        context = frame_context(client, e->xbutton.window, pwx, pwy);
         context = mouse_button_frame_context(context, e->xbutton.button);
 
+        pwx = pwy = -1;
+
         if (e->xbutton.button == button) {
             /* clicks are only valid if its released over the window */
             gint junk1, junk2;
@@ -272,7 +278,7 @@ void mouse_event(ObClient *client, XEvent *e)
 
     case MotionNotify:
         if (button) {
-            context = frame_context(client, e->xany.window);
+            context = frame_context(client, e->xmotion.window, pwx, pwy);
             context = mouse_button_frame_context(context, button);
 
             if (ABS(e->xmotion.x_root - px) >=
index db26f0d2582fe836c50e0e44a00374614e9eff14..d3c805496a44ad1688d86a3679d35e44c5a358de 100644 (file)
 #include <X11/Xcursor/Xcursor.h>
 #endif
 
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+
 RrInstance *ob_rr_inst;
 RrTheme    *ob_rr_theme;
 ObMainLoop *ob_main_loop;
@@ -201,32 +205,27 @@ gint main(gint argc, gchar **argv)
     cursors[OB_CURSOR_NORTHWEST] = load_cursor("top_left_corner",
                                                XC_top_left_corner);
 
-    /* create available keycodes */
-    keys[OB_KEY_RETURN] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Return"));
-    keys[OB_KEY_ESCAPE] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Escape"));
-    keys[OB_KEY_LEFT] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Left"));
-    keys[OB_KEY_RIGHT] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Right"));
-    keys[OB_KEY_UP] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Up"));
-    keys[OB_KEY_DOWN] =
-        XKeysymToKeycode(ob_display, XStringToKeysym("Down"));
 
     prop_startup(); /* get atoms values for the display */
     extensions_query_all(); /* find which extensions are present */
 
     if (screen_annex(program_name)) { /* it will be ours! */
         do {
+            modkeys_startup(reconfigure);
+
+            /* get the keycodes for keys we use */
+            keys[OB_KEY_RETURN] = modkeys_sym_to_code(XK_Return);
+            keys[OB_KEY_ESCAPE] = modkeys_sym_to_code(XK_Escape);
+            keys[OB_KEY_LEFT] = modkeys_sym_to_code(XK_Left);
+            keys[OB_KEY_RIGHT] = modkeys_sym_to_code(XK_Right);
+            keys[OB_KEY_UP] = modkeys_sym_to_code(XK_Up);
+            keys[OB_KEY_DOWN] = modkeys_sym_to_code(XK_Down);
+
             {
                 ObParseInst *i;
                 xmlDocPtr doc;
                 xmlNodePtr node;
 
-                modkeys_startup(reconfigure);
-
                 /* startup the parsing so everything can register sections
                    of the rc */
                 i = parse_startup();
index e35c93aadcfbd4dd5c9c36e20595f1cb327fdd1a..3861f7c17275b823dea47ae2864cfe9801bd27be 100644 (file)
@@ -95,6 +95,7 @@ void prop_startup()
     CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW");
     CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT");
     CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
+    CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
 
 /*   CREATE(net_wm_ping, "_NET_WM_PING"); */
 #ifdef SYNC
@@ -167,7 +168,7 @@ void prop_startup()
 
     CREATE(openbox_pid, "_OPENBOX_PID");
     CREATE(openbox_config, "_OPENBOX_CONFIG");
-    CREATE(openbox_wm_state_undecorated, "_OPENBOX_WM_STATE_UNDECORATED");
+    CREATE(openbox_wm_state_undecorated, "_OB_WM_STATE_UNDECORATED");
     CREATE(openbox_control, "_OPENBOX_CONTROL");
 }
 
index f8b44a73027ef678ef84244aad379a54af004da3..4f45b6d4817b9895c6fe167580eb639e5924ef08 100644 (file)
@@ -132,6 +132,7 @@ typedef struct Atoms {
     Atom net_wm_user_time;
     Atom net_wm_user_time_window;
     Atom net_frame_extents;
+    Atom net_request_frame_extents;
 
     /* application protocols */
 /*  Atom net_wm_ping; */
index 9265c73b3499100e8e107c7d16005a6cb2432114..190468aa93dda8478313b52fc0e48bf7e3a9170b 100644 (file)
@@ -275,6 +275,7 @@ gboolean screen_annex(const gchar *program_name)
     supported[i++] = prop_atoms.net_wm_user_time;
     supported[i++] = prop_atoms.net_wm_user_time_window;
     supported[i++] = prop_atoms.net_frame_extents;
+    supported[i++] = prop_atoms.net_request_frame_extents;
     supported[i++] = prop_atoms.net_startup_id;
 #ifdef SYNC
     supported[i++] = prop_atoms.net_wm_sync_request;
index bcf80ad0e8f72c7a60bd04ce30897f3468fa0d8f..2c189ed087ac5e240a06ca3474a3dba0da3b76cf 100644 (file)
@@ -175,7 +175,7 @@ static gboolean session_connect()
                                 SmcSaveCompleteProcMask |
                                 SmcShutdownCancelledProcMask,
                                 &cb, oldid, &ob_sm_id,
-                                SM_ERR_LEN, sm_err);
+                                SM_ERR_LEN-1, sm_err);
     g_free(oldid);
     if (sm_conn == NULL)
         ob_debug("Failed to connect to session manager: %s\n", sm_err);
@@ -394,6 +394,7 @@ static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
 
     if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
         ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
+        g_free(savedata);
         SmcSaveYourselfDone(conn, FALSE);
     }
 }
index 1ca1b768f703be12e7626bdc7aa4c7dbe4a19f87..166b9abb8182bafc8c782ca2f8a71931bdcff59e 100644 (file)
 static void measure_font(const RrInstance *inst, RrFont *f)
 {
     PangoFontMetrics *metrics;
-    gchar *locale, *p;
-
-    /* get the default language from the locale
-       (based on gtk_get_default_language in gtkmain.c) */
-    locale = g_strdup(setlocale(LC_CTYPE, NULL));
-    if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
-    if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
+    static PangoLanguage *lang = NULL;
+
+    if (lang == NULL) {
+#if PANGO_VERSION_CHECK(1,16,0)
+        lang = pango_language_get_default();
+#else
+        gchar *locale, *p;
+        /* get the default language from the locale
+           (based on gtk_get_default_language in gtkmain.c) */
+        locale = g_strdup(setlocale(LC_CTYPE, NULL));
+        if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
+        if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
+        lang = pango_language_from_string(locale);
+        g_free(locale);
+#endif
+    }
 
     /* measure the ascent and descent */
-    metrics = pango_context_get_metrics(inst->pango, f->font_desc,
-                                        pango_language_from_string(locale));
+    metrics = pango_context_get_metrics(inst->pango, f->font_desc, lang);
     f->ascent = pango_font_metrics_get_ascent(metrics);
     f->descent = pango_font_metrics_get_descent(metrics);
     pango_font_metrics_unref(metrics);
 
-    g_free(locale);
 }
 
 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
@@ -66,6 +73,8 @@ RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
     out->font_desc = pango_font_description_new();
     out->layout = pango_layout_new(inst->pango);
     out->shortcut_underline = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
+    out->shortcut_underline->start_index = 0;
+    out->shortcut_underline->end_index = 0;
 
     attrlist = pango_attr_list_new();
     /* shortcut_underline is owned by the attrlist */
@@ -219,16 +228,6 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
         break;
     }
 
-    t->font->shortcut_underline->start_index = 0;
-    t->font->shortcut_underline->end_index = 0;
-    /* the attributes are owned by the layout.
-       re-add the attributes to the layout after changing the
-       start and end index */
-    attrlist = pango_layout_get_attributes(t->font->layout);
-    pango_attr_list_ref(attrlist);
-    pango_layout_set_attributes(t->font->layout, attrlist);
-    pango_attr_list_unref(attrlist);
-
     if (t->shadow_offset_x || t->shadow_offset_y) {
         c.color.red = t->shadow_color->r | t->shadow_color->r << 8;
         c.color.green = t->shadow_color->g | t->shadow_color->g << 8;
@@ -270,4 +269,16 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
     pango_xft_render_layout_line
         (d, &c, pango_layout_get_line(t->font->layout, 0),
          x * PANGO_SCALE, y * PANGO_SCALE);
+
+    if (t->shortcut) {
+        t->font->shortcut_underline->start_index = 0;
+        t->font->shortcut_underline->end_index = 0;
+        /* the attributes are owned by the layout.
+           re-add the attributes to the layout after changing the
+           start and end index */
+        attrlist = pango_layout_get_attributes(t->font->layout);
+        pango_attr_list_ref(attrlist);
+        pango_layout_set_attributes(t->font->layout, attrlist);
+        pango_attr_list_unref(attrlist);
+    }
 }
index 84561ef11145eac5d212da052bfc7678e6001ee7..a32a11f16bba9a6b2c571f16773920c10d4b2dca 100644 (file)
@@ -131,6 +131,7 @@ RrTheme* RrThemeNew(const RrInstance *inst, gchar *name,
             winjust = RR_JUSTIFY_RIGHT;
         else if (!g_ascii_strcasecmp(str, "center"))
             winjust = RR_JUSTIFY_CENTER;
+        g_free(str);
     }
 
     if (menu_title_font) {
@@ -145,6 +146,7 @@ RrTheme* RrThemeNew(const RrInstance *inst, gchar *name,
             mtitlejust = RR_JUSTIFY_RIGHT;
         else if (!g_ascii_strcasecmp(str, "center"))
             mtitlejust = RR_JUSTIFY_CENTER;
+        g_free(str);
     }
 
     if (menu_item_font) {