Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Mon, 11 Jan 2010 21:20:53 +0000 (16:20 -0500)
committerDana Jansens <danakj@orodu.net>
Mon, 11 Jan 2010 21:20:53 +0000 (16:20 -0500)
Conflicts:

configure.ac
data/rc.xml
openbox/client.c
openbox/event.c
openbox/focus_cycle.c
openbox/focus_cycle_popup.c
openbox/openbox.c
openbox/prop.c
openbox/prop.h
openbox/screen.c
parser/parse.c
version.h.in

26 files changed:
configure.ac
data/rc.xml
obt/prop.c
obt/prop.h
openbox/client.c
openbox/client.h
openbox/event.c
openbox/focus.c
openbox/focus.h
openbox/focus_cycle.c
openbox/focus_cycle.h
openbox/focus_cycle_popup.c
openbox/focus_cycle_popup.h
openbox/menuframe.c
openbox/menuframe.h
openbox/misc.h
openbox/openbox.c
openbox/prop.c [new file with mode: 0644]
openbox/prop.h [new file with mode: 0644]
openbox/screen.c
parser/parse.c [new file with mode: 0644]
po/hu.po
po/ja.po
po/lv.po
tools/obxprop/obxprop.c
version.h.in [new file with mode: 0644]

index 99b416a..57f126a 100644 (file)
@@ -3,6 +3,9 @@ AC_INIT([openbox], [3.5.0-rc1], [http://bugzilla.icculus.org])
 AM_INIT_AUTOMAKE
 AC_CONFIG_SRCDIR([openbox/openbox.c])
 
+OB_VERSION=$PACKAGE_VERSION
+AC_SUBST(OB_VERSION)
+
 dnl Making releases:
 dnl   RR_MICRO_VERSION += 1;
 dnl   RR_INTERFACE_AGE += 1;
@@ -206,6 +209,7 @@ AC_CONFIG_FILES([
   obt/obt-3.5.pc
   obrender/version.h
   obt/version.h
+  version.h
 ])
 AC_CONFIG_COMMANDS([doc],
                    [test -d doc || mkdir doc])
index aa36192..ecc22bb 100644 (file)
   # you may use one or more of the name/class/role/type rules to specify
   # windows to match
 
-  <application name="the window's _OB_NAME property (see obxprop)"
-              class="the window's _OB_CLASS property (see obxprop)"
-               role="the window's _OB_ROLE property (see obxprop)"
-               type="the window's _NET_WM_WINDOW_TYPE (see obxprob)..
-                      (if unspecified, then it is 'dialog' for child windows)
-                      one of: normal, dialog, splash, utility, menu, toolbar,
-                              dock, desktop">
-  # the name or the class can be set, or both. this is used to match
-  # windows when they appear. role can optionally be set as well, to
-  # further restrict your matches.
+  <application name="the window's _OB_APP_NAME property (see obxprop)"
+              class="the window's _OB_APP_CLASS property (see obxprop)"
+               role="the window's _OB_APP_ROLE property (see obxprop)"
+               type="the window's _OB_APP_TYPE property (see obxprob)..
+                      (if unspecified, then it is 'dialog' for child windows)">
+  # you may set only one of name/class/role/type, or you may use more than one
+  # together to restrict your matches.
 
   # the name, class, and role use simple wildcard matching such as those
   # used by a shell. you can use * to match any characters and ? to match
   # order that they appear in this list
 
 
-    # each element can be left out or set to 'default' to specify to not 
+    # each rule element can be left out or set to 'default' to specify to not 
     # change that attribute of the window
 
     <decor>yes</decor>
index f4c8db1..3af9c7d 100644 (file)
@@ -190,9 +190,11 @@ void obt_prop_startup(void)
     CREATE_(OB_WM_ACTION_UNDECORATE);
     CREATE_(OB_WM_STATE_UNDECORATED);
     CREATE_(OB_CONTROL);
-    CREATE_(OB_ROLE);
-    CREATE_(OB_NAME);
-    CREATE_(OB_CLASS);
+    CREATE_(OB_VERSION);
+    CREATE_(OB_APP_ROLE);
+    CREATE_(OB_APP_NAME);
+    CREATE_(OB_APP_CLASS);
+    CREATE_(OB_APP_TYPE);
 }
 
 Atom obt_prop_atom(ObtPropAtom a)
index 52c1de1..0a471cd 100644 (file)
@@ -211,9 +211,11 @@ typedef enum {
     OBT_PROP_OB_THEME,
     OBT_PROP_OB_CONFIG_FILE,
     OBT_PROP_OB_CONTROL,
-    OBT_PROP_OB_ROLE,
-    OBT_PROP_OB_NAME,
-    OBT_PROP_OB_CLASS,
+    OBT_PROP_OB_VERSION,
+    OBT_PROP_OB_APP_ROLE,
+    OBT_PROP_OB_APP_NAME,
+    OBT_PROP_OB_APP_CLASS,
+    OBT_PROP_OB_APP_TYPE,
 
     OBT_PROP_NUM_ATOMS
 } ObtPropAtom;
index 4b70376..fd2afed 100644 (file)
@@ -31,6 +31,7 @@
 #include "grab.h"
 #include "prompt.h"
 #include "focus.h"
+#include "focus_cycle.h"
 #include "stacking.h"
 #include "openbox.h"
 #include "group.h"
@@ -75,7 +76,7 @@ static RrImage *client_default_icon     = NULL;
 static void client_get_all(ObClient *self, gboolean real);
 static void client_get_startup_id(ObClient *self);
 static void client_get_session_ids(ObClient *self);
-static void client_save_session_ids(ObClient *self);
+static void client_save_app_rule_values(ObClient *self);
 static void client_get_area(ObClient *self);
 static void client_get_desktop(ObClient *self);
 static void client_get_state(ObClient *self);
@@ -223,6 +224,7 @@ void client_manage(Window window, ObPrompt *prompt)
     self->obwin.type = OB_WINDOW_CLASS_CLIENT;
     self->window = window;
     self->prompt = prompt;
+    self->managed = TRUE;
 
     /* non-zero defaults */
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
@@ -551,6 +553,8 @@ void client_unmanage(ObClient *self)
 
     mouse_grab_for_client(self, FALSE);
 
+    self->managed = FALSE;
+
     /* remove the window from our save set, unless we are managing an internal
        ObPrompt window */
     if (!self->prompt)
@@ -1078,7 +1082,9 @@ static void client_get_all(ObClient *self, gboolean real)
     /* get the session related properties, these can change decorations
        from per-app settings */
     client_get_session_ids(self);
-    client_save_session_ids(self);
+
+    /* save the values of the variables used for app rule matching */
+    client_save_app_rule_values(self);
 
     /* now we got everything that can affect the decorations */
     if (!real)
@@ -1912,6 +1918,8 @@ void client_update_wmhints(ObClient *self)
 
         XFree(hints);
     }
+
+    focus_cycle_addremove(self, TRUE);
 }
 
 void client_update_title(ObClient *self)
@@ -2292,13 +2300,36 @@ static void client_get_session_ids(ObClient *self)
     }
 }
 
-/*! Save the session IDs as seen by Openbox when the window mapped, so that
-  users can still access them later if the app changes them */
-static void client_save_session_ids(ObClient *self)
+/*! Save the properties used for app matching rules, as seen by Openbox when
+  the window mapped, so that users can still access them later if the app
+  changes them */
+static void client_save_app_rule_values(ObClient *self)
 {
-    OBT_PROP_SETS(self->window, OB_ROLE, utf8, self->role);
-    OBT_PROP_SETS(self->window, OB_NAME, utf8, self->name);
-    OBT_PROP_SETS(self->window, OB_CLASS, utf8, self->class);
+    const gchar *type;
+
+    OBT_PROP_SETS(self->window, OB_APP_ROLE, utf8, self->role);
+    OBT_PROP_SETS(self->window, OB_APP_NAME, utf8, self->name);
+    OBT_PROP_SETS(self->window, OB_APP_CLASS, utf8, self->class);
+
+    switch (self->type) {
+    case OB_CLIENT_TYPE_NORMAL:
+        type = "normal"; break;
+    case OB_CLIENT_TYPE_DIALOG:
+        type = "dialog"; break;
+    case OB_CLIENT_TYPE_UTILITY:
+        type = "utility"; break;
+    case OB_CLIENT_TYPE_MENU:
+        type = "menu"; break;
+    case OB_CLIENT_TYPE_TOOLBAR:
+        type = "toolbar"; break;
+    case OB_CLIENT_TYPE_SPLASH:
+        type = "splash"; break;
+    case OB_CLIENT_TYPE_DESKTOP:
+        type = "desktop"; break;
+    case OB_CLIENT_TYPE_DOCK:
+        type = "dock"; break;
+    }
+    OBT_PROP_SETS(self->window, OB_APP_TYPE, utf8, type);
 }
 
 static void client_change_wm_state(ObClient *self)
@@ -3149,7 +3180,7 @@ static void client_iconify_recursive(ObClient *self,
                 self->iconic = iconic;
 
                 /* update the focus lists.. iconic windows go to the bottom of
-                   the list */
+                   the list. this will also call focus_cycle_addremove(). */
                 focus_order_to_bottom(self);
 
                 changed = TRUE;
@@ -3161,9 +3192,10 @@ static void client_iconify_recursive(ObClient *self,
                 self->desktop != DESKTOP_ALL)
                 client_set_desktop(self, screen_desktop, FALSE, FALSE);
 
-            /* this puts it after the current focused window */
-            focus_order_remove(self);
-            focus_order_add_new(self);
+            /* this puts it after the current focused window, this will
+               also cause focus_cycle_addremove() to be called for the
+               client */
+            focus_order_like_new(self);
 
             changed = TRUE;
         }
@@ -3496,6 +3528,8 @@ static void client_set_desktop_recursive(ObClient *self,
             /* the new desktop's geometry may be different, so we may need to
                resize, for example if we are maximized */
             client_reconfigure(self, FALSE);
+
+        focus_cycle_addremove(self, FALSE);
     }
 
     /* move all transients */
@@ -3511,6 +3545,8 @@ void client_set_desktop(ObClient *self, guint target,
 {
     self = client_search_top_direct_parent(self);
     client_set_desktop_recursive(self, target, donthide, dontraise);
+
+    focus_cycle_addremove(NULL, TRUE);
 }
 
 gboolean client_is_direct_child(ObClient *parent, ObClient *child)
@@ -3724,6 +3760,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
         client_hilite(self, demands_attention);
 
     client_change_state(self); /* change the hint to reflect these changes */
+
+    focus_cycle_addremove(self, TRUE);
 }
 
 ObClient *client_focus_target(ObClient *self)
index a361e36..7370efc 100644 (file)
@@ -73,6 +73,7 @@ struct _ObClient
 {
     ObWindow obwin;
     Window  window;
+    gboolean managed;
 
     /*! If this client is managing an ObPrompt window, then this is set to the
       prompt */
index e279c9d..45ae101 100644 (file)
@@ -1816,7 +1816,12 @@ static gboolean event_handle_menu_input(XEvent *ev)
 
             else if (ob_keycode_match(keycode, OB_KEY_RIGHT)) {
                 /* Right goes to the selected submenu */
-                if (frame->child) menu_frame_select_next(frame->child);
+                if (frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                {
+                    /* make sure it is visible */
+                    menu_frame_select(frame, frame->selected, TRUE);
+                    menu_frame_select_next(frame->child);
+                }
                 ret = TRUE;
             }
 
@@ -1829,6 +1834,16 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 menu_frame_select_next(frame);
                 ret = TRUE;
             }
+
+            else if (ob_keycode_match(keycode, OB_KEY_HOME)) {
+                menu_frame_select_first(frame);
+                ret = TRUE;
+            }
+
+            else if (ob_keycode_match(keycode, OB_KEY_END)) {
+                menu_frame_select_last(frame);
+                ret = TRUE;
+            }
         }
 
         /* Use KeyRelease events for running things so that the key release
index 8b4b66e..20b799f 100644 (file)
@@ -90,6 +90,9 @@ void focus_set_client(ObClient *client)
         push_to_top(client);
         /* remove hiliting from the window when it gets focused */
         client_hilite(client, FALSE);
+
+        /* make sure the focus cycle popup shows things in the right order */
+        focus_cycle_reorder();
     }
 
     /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
@@ -199,7 +202,7 @@ void focus_order_add_new(ObClient *c)
         focus_order_to_top(c);
     else {
         g_assert(!g_list_find(focus_order, c));
-        /* if there are any iconic windows, put this above them in the order,
+        /* if there are only iconic windows, put this above them in the order,
            but if there are not, then put it under the currently focused one */
         if (focus_order && ((ObClient*)focus_order->data)->iconic)
             focus_order = g_list_insert(focus_order, c, 0);
@@ -207,16 +210,20 @@ void focus_order_add_new(ObClient *c)
             focus_order = g_list_insert(focus_order, c, 1);
     }
 
-    /* in the middle of cycling..? kill it. */
-    focus_cycle_stop(c);
+    focus_cycle_addremove(c, TRUE);
 }
 
 void focus_order_remove(ObClient *c)
 {
     focus_order = g_list_remove(focus_order, c);
 
-    /* in the middle of cycling..? kill it. */
-    focus_cycle_stop(c);
+    focus_cycle_addremove(c, TRUE);
+}
+
+void focus_order_like_new(struct _ObClient *c)
+{
+    focus_order = g_list_remove(focus_order, c);
+    focus_order_add_new(c);
 }
 
 void focus_order_to_top(ObClient *c)
@@ -232,6 +239,8 @@ void focus_order_to_top(ObClient *c)
              it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
         focus_order = g_list_insert_before(focus_order, it, c);
     }
+
+    focus_cycle_reorder();
 }
 
 void focus_order_to_bottom(ObClient *c)
@@ -247,6 +256,8 @@ void focus_order_to_bottom(ObClient *c)
              it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
         focus_order = g_list_insert_before(focus_order, it, c);
     }
+
+    focus_cycle_reorder();
 }
 
 ObClient *focus_order_find_first(guint desktop)
@@ -294,8 +305,15 @@ gboolean focus_valid_target(ObClient *ft,
                             gboolean desktop_windows,
                             gboolean user_request)
 {
+    /* NOTE: if any of these things change on a client, then they should call
+       focus_cycle_addremove() to make sure the client is not shown/hidden
+       when it should not be */
+
     gboolean ok = FALSE;
 
+    /* see if the window is still managed or is going away */
+    if (!ft->managed) return FALSE;
+
     /* it's on this desktop unless you want all desktops.
 
        do this check first because it will usually filter out the most
index f926d01..47d86d8 100644 (file)
@@ -58,6 +58,10 @@ void focus_order_remove(struct _ObClient *c);
 /*! Move a client to the top of the focus order */
 void focus_order_to_top(struct _ObClient *c);
 
+/*! Move a client to where it would be if it was newly added to the focus order
+ */
+void focus_order_like_new(struct _ObClient *c);
+
 /*! Move a client to the bottom of the focus order (keeps iconic windows at the
   very bottom always though). */
 void focus_order_to_bottom(struct _ObClient *c);
index 4e04477..e4c370e 100644 (file)
 #include <X11/Xlib.h>
 #include <glib.h>
 
+typedef enum {
+    OB_CYCLE_NONE = 0,
+    OB_CYCLE_NORMAL,
+    OB_CYCLE_DIRECTIONAL
+} ObCycleType;
+
 ObClient       *focus_cycle_target = NULL;
+static ObCycleType focus_cycle_type = OB_CYCLE_NONE;
 static gboolean focus_cycle_iconic_windows;
 static gboolean focus_cycle_all_desktops;
 static gboolean focus_cycle_dock_windows;
@@ -50,17 +57,40 @@ void focus_cycle_shutdown(gboolean reconfig)
     if (reconfig) return;
 }
 
-void focus_cycle_stop(ObClient *ifclient)
+void focus_cycle_addremove(ObClient *c, gboolean redraw)
 {
-    /* stop focus cycling if the given client is a valid focus target,
-       and so the cycling is being disrupted */
-    if (focus_cycle_target &&
-        ((ifclient && (ifclient == focus_cycle_target ||
-                       focus_cycle_popup_is_showing(ifclient))) ||
-         !ifclient))
-    {
-        focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE);
-        focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
+    if (!focus_cycle_type)
+        return;
+
+    if (focus_cycle_type == OB_CYCLE_DIRECTIONAL) {
+        if (c && focus_cycle_target == c) {
+            focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE,
+                                    TRUE, TRUE, TRUE);
+        }
+    }
+    else if (c && redraw) {
+        gboolean v, s;
+
+        v = focus_cycle_valid(c);
+        s = focus_cycle_popup_is_showing(c);
+
+        if (v != s)
+            focus_cycle_reorder();
+    }
+    else if (redraw) {
+        focus_cycle_reorder();
+    }
+}
+
+void focus_cycle_reorder()
+{
+    if (focus_cycle_type == OB_CYCLE_NORMAL) {
+        focus_cycle_target = focus_cycle_popup_refresh(focus_cycle_target,
+                                                       TRUE);
+        focus_cycle_update_indicator(focus_cycle_target);
+        if (!focus_cycle_target)
+            focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE,
+                        TRUE, TRUE, TRUE, TRUE, TRUE);
     }
 }
 
@@ -115,16 +145,11 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
             if (it == NULL) it = g_list_last(list);
         }
         ft = it->data;
-        if (focus_valid_target(ft, screen_desktop, TRUE,
-                               focus_cycle_iconic_windows,
-                               focus_cycle_all_desktops,
-                               focus_cycle_dock_windows,
-                               focus_cycle_desktop_windows,
-                               FALSE))
-        {
+        if (focus_cycle_valid(ft)) {
             if (interactive) {
                 if (ft != focus_cycle_target) { /* prevents flicker */
                     focus_cycle_target = ft;
+                    focus_cycle_type = OB_CYCLE_NORMAL;
                     focus_cycle_draw_indicator(showbar ? ft : NULL);
                 }
                 /* same arguments as focus_target_valid */
@@ -137,6 +162,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
                 return focus_cycle_target;
             } else if (ft != focus_cycle_target) {
                 focus_cycle_target = ft;
+                focus_cycle_type = OB_CYCLE_NORMAL;
                 done = TRUE;
                 break;
             }
@@ -147,6 +173,7 @@ done_cycle:
     if (done && !cancel) ret = focus_cycle_target;
 
     focus_cycle_target = NULL;
+    focus_cycle_type = OB_CYCLE_NONE;
     g_list_free(order);
     order = NULL;
 
@@ -186,9 +213,7 @@ static ObClient *focus_find_directional(ObClient *c, ObDirection dir,
         /* the currently selected window isn't interesting */
         if (cur == c)
             continue;
-        if (!focus_valid_target(it->data, screen_desktop,
-                                TRUE, FALSE, FALSE, dock_windows,
-                                desktop_windows, FALSE))
+        if (!focus_cycle_valid(it->data))
             continue;
 
         /* find the centre coords of this window, from the
@@ -292,16 +317,15 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows,
         GList *it;
 
         for (it = focus_order; it; it = g_list_next(it))
-            if (focus_valid_target(it->data, screen_desktop, TRUE,
-                                   focus_cycle_iconic_windows,
-                                   focus_cycle_all_desktops,
-                                   focus_cycle_dock_windows,
-                                   focus_cycle_desktop_windows, FALSE))
+            if (focus_cycle_valid(it->data)) {
                 ft = it->data;
+                break;
+            }
     }
 
     if (ft && ft != focus_cycle_target) {/* prevents flicker */
         focus_cycle_target = ft;
+        focus_cycle_type = OB_CYCLE_DIRECTIONAL;
         if (!interactive)
             goto done_cycle;
         focus_cycle_draw_indicator(showbar ? ft : NULL);
@@ -320,9 +344,20 @@ done_cycle:
 
     first = NULL;
     focus_cycle_target = NULL;
+    focus_cycle_type = OB_CYCLE_NONE;
 
     focus_cycle_draw_indicator(NULL);
     focus_cycle_popup_single_hide();
 
     return ret;
 }
+
+gboolean focus_cycle_valid(struct _ObClient *client)
+{
+    return focus_valid_target(client, screen_desktop, TRUE,
+                              focus_cycle_iconic_windows,
+                              focus_cycle_all_desktops,
+                              focus_cycle_dock_windows,
+                              focus_cycle_desktop_windows,
+                              FALSE);
+}
index c31abc8..ab477d6 100644 (file)
@@ -48,6 +48,10 @@ struct _ObClient* focus_directional_cycle(ObDirection dir,
                                           gboolean dialog,
                                           gboolean done, gboolean cancel);
 
-void focus_cycle_stop(struct _ObClient *ifclient);
+/*! Set @redraw to FALSE if there are more clients to be added/removed first */
+void focus_cycle_addremove(struct _ObClient *ifclient, gboolean redraw);
+void focus_cycle_reorder();
+
+gboolean focus_cycle_valid(struct _ObClient *client);
 
 #endif
index 4248441..08016fe 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include "focus_cycle_popup.h"
+#include "focus_cycle.h"
 #include "popup.h"
 #include "client.h"
 #include "screen.h"
@@ -98,15 +99,12 @@ static ObFocusCyclePopup popup;
 /*! This popup shows a single window */
 static ObIconPopup *single_popup;
 
-static gchar *popup_get_name (ObClient *c);
-static void   popup_setup    (ObFocusCyclePopup *p,
-                              gboolean create_targets,
-                              gboolean iconic_windows,
-                              gboolean all_desktops,
-                              gboolean dock_windows,
-                              gboolean desktop_windows);
-static void   popup_render   (ObFocusCyclePopup *p,
-                              const ObClient *c);
+static gchar   *popup_get_name (ObClient *c);
+static gboolean popup_setup    (ObFocusCyclePopup *p,
+                                gboolean create_targets,
+                                gboolean refresh_targets);
+static void     popup_render   (ObFocusCyclePopup *p,
+                                const ObClient *c);
 
 static Window create_window(Window parent, guint bwidth, gulong mask,
                             XSetWindowAttributes *attr)
@@ -242,12 +240,35 @@ void focus_cycle_popup_shutdown(gboolean reconfig)
     RrAppearanceFree(popup.a_bg);
 }
 
-static void popup_setup(ObFocusCyclePopup *p, gboolean create_targets,
-                        gboolean iconic_windows, gboolean all_desktops,
-                        gboolean dock_windows, gboolean desktop_windows)
+static void popup_target_free(ObFocusCyclePopupTarget *t)
+{
+    RrImageUnref(t->icon);
+    g_free(t->text);
+    XDestroyWindow(obt_display, t->iconwin);
+    XDestroyWindow(obt_display, t->textwin);
+    g_free(t);
+}
+
+static gboolean popup_setup(ObFocusCyclePopup *p, gboolean create_targets,
+                            gboolean refresh_targets)
 {
     gint maxwidth, n;
     GList *it;
+    GList *rtargets; /* old targets for refresh */
+    GList *rtlast;
+    gboolean change;
+
+    if (refresh_targets) {
+        rtargets = p->targets;
+        rtlast = g_list_last(rtargets);
+        p->targets = NULL;
+        p->n_targets = 0;
+        change = FALSE;
+    }
+    else {
+        rtargets = rtlast = NULL;
+        change = TRUE;
+    }
 
     g_assert(p->targets == NULL);
     g_assert(p->n_targets == 0);
@@ -261,39 +282,82 @@ static void popup_setup(ObFocusCyclePopup *p, gboolean create_targets,
     for (it = g_list_last(focus_order); it; it = g_list_previous(it)) {
         ObClient *ft = it->data;
 
-        if (focus_valid_target(ft, screen_desktop, TRUE,
-                               iconic_windows,
-                               all_desktops,
-                               dock_windows,
-                               desktop_windows,
-                               FALSE))
-        {
-            gchar *text = popup_get_name(ft);
+        if (focus_cycle_valid(ft)) {
+            GList *rit;
 
-            /* measure */
-            p->a_text->texture[0].data.text.string = text;
-            maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
+            /* reuse the target if possible during refresh */
+            for (rit = rtlast; rit; rit = g_list_previous(rit)) {
+                ObFocusCyclePopupTarget *t = rit->data;
+                if (t->client == ft) {
+                    if (rit == rtlast)
+                        rtlast = g_list_previous(rit);
+                    rtargets = g_list_remove_link(rtargets, rit);
 
-            if (!create_targets) {
-                g_free(text);
-            } else {
-                ObFocusCyclePopupTarget *t = g_new(ObFocusCyclePopupTarget, 1);
+                    p->targets = g_list_concat(rit, p->targets);
+                    ++n;
+
+                    if (rit != rtlast)
+                        change = TRUE; /* order changed */
+                    break;
+                }
+            }
+
+            if (!rit) {
+                gchar *text = popup_get_name(ft);
+
+                /* measure */
+                p->a_text->texture[0].data.text.string = text;
+                maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
 
-                t->client = ft;
-                t->text = text;
-                t->icon = client_icon(t->client);
-                RrImageRef(t->icon); /* own the icon so it won't go away */
-                t->iconwin = create_window(p->bg, 0, 0, NULL);
-                t->textwin = create_window(p->bg, 0, 0, NULL);
+                if (!create_targets) {
+                    g_free(text);
+                } else {
+                    ObFocusCyclePopupTarget *t =
+                        g_new(ObFocusCyclePopupTarget, 1);
+
+                    t->client = ft;
+                    t->text = text;
+                    t->icon = client_icon(t->client);
+                    RrImageRef(t->icon); /* own the icon so it won't go away */
+                    t->iconwin = create_window(p->bg, 0, 0, NULL);
+                    t->textwin = create_window(p->bg, 0, 0, NULL);
 
-                p->targets = g_list_prepend(p->targets, t);
-                ++n;
+                    p->targets = g_list_prepend(p->targets, t);
+                    ++n;
+
+                    change = TRUE; /* added a window */
+                }
             }
         }
     }
 
+    if (rtargets) {
+        change = TRUE; /* removed a window */
+
+        while (rtargets) {
+            popup_target_free(rtargets->data);
+            rtargets = g_list_delete_link(rtargets, rtargets);
+        }
+    }
+
     p->n_targets = n;
-    p->maxtextw = maxwidth;
+    if (refresh_targets)
+        /* don't shrink when refreshing */
+        p->maxtextw = MAX(p->maxtextw, maxwidth);
+    else
+        p->maxtextw = maxwidth;
+
+    return change;
+}
+
+static void popup_cleanup(void)
+{
+    while(popup.targets) {
+        popup_target_free(popup.targets->data);
+        popup.targets = g_list_delete_link(popup.targets, popup.targets);
+    }
+    popup.n_targets = 0;
+    popup.last_target = NULL;
 }
 
 static gchar *popup_get_name(ObClient *c)
@@ -652,8 +716,7 @@ void focus_cycle_popup_show(ObClient *c, gboolean iconic_windows,
 
     /* do this stuff only when the dialog is first showing */
     if (!popup.mapped) {
-        popup_setup(&popup, TRUE, iconic_windows, all_desktops, 
-                    dock_windows, desktop_windows);
+        popup_setup(&popup, TRUE, FALSE);
         /* this is fixed once the dialog is shown */
         popup.mode = mode;
     }
@@ -683,19 +746,7 @@ void focus_cycle_popup_hide(void)
 
     popup.mapped = FALSE;
 
-    while(popup.targets) {
-        ObFocusCyclePopupTarget *t = popup.targets->data;
-
-        RrImageUnref(t->icon);
-        g_free(t->text);
-        XDestroyWindow(obt_display, t->iconwin);
-        XDestroyWindow(obt_display, t->textwin);
-        g_free(t);
-
-        popup.targets = g_list_delete_link(popup.targets, popup.targets);
-    }
-    popup.n_targets = 0;
-    popup.last_target = NULL;
+    popup_cleanup();
 }
 
 void focus_cycle_popup_single_show(struct _ObClient *c,
@@ -712,8 +763,7 @@ void focus_cycle_popup_single_show(struct _ObClient *c,
     if (!popup.mapped) {
         Rect *a;
 
-        popup_setup(&popup, FALSE, iconic_windows, all_desktops,
-                    dock_windows, desktop_windows);
+        popup_setup(&popup, FALSE, FALSE);
         g_assert(popup.targets == NULL);
 
         /* position the popup */
@@ -738,16 +788,67 @@ void focus_cycle_popup_single_hide(void)
     icon_popup_hide(single_popup);
 }
 
-gboolean focus_cycle_popup_is_showing(ObClient *client)
+gboolean focus_cycle_popup_is_showing(ObClient *c)
 {
     if (popup.mapped) {
         GList *it;
 
         for (it = popup.targets; it; it = g_list_next(it)) {
             ObFocusCyclePopupTarget *t = it->data;
-            if (t->client == client)
+            if (t->client == c)
                 return TRUE;
         }
     }
     return FALSE;
 }
+
+static ObClient* popup_revert(ObClient *target)
+{
+    GList *it, *itt;
+
+    for (it = popup.targets; it; it = g_list_next(it)) {
+        ObFocusCyclePopupTarget *t = it->data;
+        if (t->client == target) {
+            /* move to a previous window if possible */
+            for (itt = it->prev; itt; itt = g_list_previous(itt)) {
+                ObFocusCyclePopupTarget *t2 = itt->data;
+                if (focus_cycle_valid(t2->client))
+                    return t2->client;
+            }
+
+            /* otherwise move to a following window if possible */
+            for (itt = it->next; itt; itt = g_list_next(itt)) {
+                ObFocusCyclePopupTarget *t2 = itt->data;
+                if (focus_cycle_valid(t2->client))
+                    return t2->client;
+            }
+
+            /* otherwise, we can't go anywhere there is nowhere valid to go */
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+ObClient* focus_cycle_popup_refresh(ObClient *target,
+                                    gboolean redraw)
+{
+    if (!popup.mapped) return NULL;
+
+    if (!focus_cycle_valid(target))
+        target = popup_revert(target);
+
+    redraw = popup_setup(&popup, TRUE, TRUE) && redraw;
+
+    if (!target && popup.targets)
+        target = ((ObFocusCyclePopupTarget*)popup.targets->data)->client;
+
+    if (target && redraw) {
+        popup.mapped = FALSE;
+        popup_render(&popup, target);
+        XFlush(obt_display);
+        popup.mapped = TRUE;
+    }
+
+    return target;
+}
index ad76491..b085f9a 100644 (file)
@@ -46,7 +46,13 @@ void focus_cycle_popup_single_show(struct _ObClient *c,
                                    gboolean desktop_windows);
 void focus_cycle_popup_single_hide(void);
 
-/*! Returns TRUE if the popup is showing the client, otherwise FALSE. */
-gboolean focus_cycle_popup_is_showing(struct _ObClient *client);
+gboolean focus_cycle_popup_is_showing(struct _ObClient *c);
+
+/*! Redraws the focus cycle popup, and returns the current target.  If
+    the target given to the function is no longer valid, this will return
+    a different target that is valid, and which should be considered the
+    current focus cycling target. */
+struct _ObClient *focus_cycle_popup_refresh(struct _ObClient *target,
+                                            gboolean redraw);
 
 #endif
index 57f2943..b235f5e 100644 (file)
@@ -1300,7 +1300,7 @@ void menu_frame_select_previous(ObMenuFrame *self)
             }
         }
     }
-    menu_frame_select(self, it ? it->data : NULL, TRUE);
+    menu_frame_select(self, it ? it->data : NULL, FALSE);
 }
 
 void menu_frame_select_next(ObMenuFrame *self)
@@ -1325,5 +1325,37 @@ void menu_frame_select_next(ObMenuFrame *self)
             }
         }
     }
-    menu_frame_select(self, it ? it->data : NULL, TRUE);
+    menu_frame_select(self, it ? it->data : NULL, FALSE);
+}
+
+void menu_frame_select_first(ObMenuFrame *self)
+{
+    GList *it = NULL;
+
+    if (self->entries) {
+        for (it = self->entries; it; it = g_list_next(it)) {
+            ObMenuEntryFrame *e = it->data;
+            if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                break;
+            if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
+                break;
+        }
+    }
+    menu_frame_select(self, it ? it->data : NULL, FALSE);
+}
+
+void menu_frame_select_last(ObMenuFrame *self)
+{
+    GList *it = NULL;
+
+    if (self->entries) {
+        for (it = g_list_last(self->entries); it; it = g_list_previous(it)) {
+            ObMenuEntryFrame *e = it->data;
+            if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                break;
+            if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
+                break;
+        }
+    }
+    menu_frame_select(self, it ? it->data : NULL, FALSE);
 }
index a57b0dc..aa32b21 100644 (file)
@@ -127,6 +127,8 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry,
                        gboolean immediate);
 void menu_frame_select_previous(ObMenuFrame *self);
 void menu_frame_select_next(ObMenuFrame *self);
+void menu_frame_select_first(ObMenuFrame *self);
+void menu_frame_select_last(ObMenuFrame *self);
 
 ObMenuFrame* menu_frame_under(gint x, gint y);
 ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y);
index c1ec407..68403f4 100644 (file)
@@ -53,6 +53,8 @@ typedef enum
     OB_KEY_DOWN,
     OB_KEY_TAB,
     OB_KEY_SPACE,
+    OB_KEY_HOME,
+    OB_KEY_END,
     OB_NUM_KEYS
 } ObKey;
 
index 792dae2..6988908 100644 (file)
@@ -224,6 +224,8 @@ gint main(gint argc, gchar **argv)
             keys[OB_KEY_DOWN] = obt_keyboard_keysym_to_keycode(XK_Down);
             keys[OB_KEY_TAB] = obt_keyboard_keysym_to_keycode(XK_Tab);
             keys[OB_KEY_SPACE] = obt_keyboard_keysym_to_keycode(XK_space);
+            keys[OB_KEY_HOME] = obt_keyboard_keysym_to_keycode(XK_Home);
+            keys[OB_KEY_END] = obt_keyboard_keysym_to_keycode(XK_End);
 
             {
                 ObtXmlInst *i;
@@ -411,6 +413,8 @@ gint main(gint argc, gchar **argv)
             g_free(keys[OB_KEY_DOWN]);
             g_free(keys[OB_KEY_TAB]);
             g_free(keys[OB_KEY_SPACE]);
+            g_free(keys[OB_KEY_HOME]);
+            g_free(keys[OB_KEY_END]);
         } while (reconfigure);
     }
 
diff --git a/openbox/prop.c b/openbox/prop.c
new file mode 100644 (file)
index 0000000..5184eda
--- /dev/null
@@ -0,0 +1,479 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   prop.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "prop.h"
+#include "openbox.h"
+
+#include <X11/Xatom.h>
+
+Atoms prop_atoms;
+
+#define CREATE(var, name) (prop_atoms.var = \
+                           XInternAtom(ob_display, name, FALSE))
+
+void prop_startup(void)
+{
+    CREATE(cardinal, "CARDINAL");
+    CREATE(window, "WINDOW");
+    CREATE(pixmap, "PIXMAP");
+    CREATE(atom, "ATOM");
+    CREATE(string, "STRING");
+    CREATE(utf8, "UTF8_STRING");
+
+    CREATE(manager, "MANAGER");
+
+    CREATE(wm_colormap_windows, "WM_COLORMAP_WINDOWS");
+    CREATE(wm_protocols, "WM_PROTOCOLS");
+    CREATE(wm_state, "WM_STATE");
+    CREATE(wm_change_state, "WM_CHANGE_STATE");
+    CREATE(wm_delete_window, "WM_DELETE_WINDOW");
+    CREATE(wm_take_focus, "WM_TAKE_FOCUS");
+    CREATE(wm_name, "WM_NAME");
+    CREATE(wm_icon_name, "WM_ICON_NAME");
+    CREATE(wm_class, "WM_CLASS");
+    CREATE(wm_window_role, "WM_WINDOW_ROLE");
+    CREATE(wm_client_machine, "WM_CLIENT_MACHINE");
+    CREATE(wm_command, "WM_COMMAND");
+    CREATE(wm_client_leader, "WM_CLIENT_LEADER");
+    CREATE(wm_transient_for, "WM_TRANSIENT_FOR");
+    CREATE(motif_wm_hints, "_MOTIF_WM_HINTS");
+    CREATE(motif_wm_info, "_MOTIF_WM_INFO");
+
+    CREATE(sm_client_id, "SM_CLIENT_ID");
+
+    CREATE(net_wm_full_placement, "_NET_WM_FULL_PLACEMENT");
+
+    CREATE(net_supported, "_NET_SUPPORTED");
+    CREATE(net_client_list, "_NET_CLIENT_LIST");
+    CREATE(net_client_list_stacking, "_NET_CLIENT_LIST_STACKING");
+    CREATE(net_number_of_desktops, "_NET_NUMBER_OF_DESKTOPS");
+    CREATE(net_desktop_geometry, "_NET_DESKTOP_GEOMETRY");
+    CREATE(net_desktop_viewport, "_NET_DESKTOP_VIEWPORT");
+    CREATE(net_current_desktop, "_NET_CURRENT_DESKTOP");
+    CREATE(net_desktop_names, "_NET_DESKTOP_NAMES");
+    CREATE(net_active_window, "_NET_ACTIVE_WINDOW");
+/*    CREATE(net_restack_window, "_NET_RESTACK_WINDOW");*/
+    CREATE(net_workarea, "_NET_WORKAREA");
+    CREATE(net_supporting_wm_check, "_NET_SUPPORTING_WM_CHECK");
+    CREATE(net_desktop_layout, "_NET_DESKTOP_LAYOUT");
+    CREATE(net_showing_desktop, "_NET_SHOWING_DESKTOP");
+
+    CREATE(net_close_window, "_NET_CLOSE_WINDOW");
+    CREATE(net_wm_moveresize, "_NET_WM_MOVERESIZE");
+    CREATE(net_moveresize_window, "_NET_MOVERESIZE_WINDOW");
+    CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
+    CREATE(net_restack_window, "_NET_RESTACK_WINDOW");
+
+    CREATE(net_startup_id, "_NET_STARTUP_ID");
+
+    CREATE(net_wm_name, "_NET_WM_NAME");
+    CREATE(net_wm_visible_name, "_NET_WM_VISIBLE_NAME");
+    CREATE(net_wm_icon_name, "_NET_WM_ICON_NAME");
+    CREATE(net_wm_visible_icon_name, "_NET_WM_VISIBLE_ICON_NAME");
+    CREATE(net_wm_desktop, "_NET_WM_DESKTOP");
+    CREATE(net_wm_window_type, "_NET_WM_WINDOW_TYPE");
+    CREATE(net_wm_state, "_NET_WM_STATE");
+    CREATE(net_wm_strut, "_NET_WM_STRUT");
+    CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL");
+    CREATE(net_wm_icon, "_NET_WM_ICON");
+    CREATE(net_wm_icon_geometry, "_NET_WM_ICON_GEOMETRY");
+    CREATE(net_wm_pid, "_NET_WM_PID");
+    CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
+    CREATE(net_wm_user_time, "_NET_WM_USER_TIME");
+/*    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_wm_ping, "_NET_WM_PING");
+#ifdef SYNC
+    CREATE(net_wm_sync_request, "_NET_WM_SYNC_REQUEST");
+    CREATE(net_wm_sync_request_counter, "_NET_WM_SYNC_REQUEST_COUNTER");
+#endif
+
+    CREATE(net_wm_window_type_desktop, "_NET_WM_WINDOW_TYPE_DESKTOP");
+    CREATE(net_wm_window_type_dock, "_NET_WM_WINDOW_TYPE_DOCK");
+    CREATE(net_wm_window_type_toolbar, "_NET_WM_WINDOW_TYPE_TOOLBAR");
+    CREATE(net_wm_window_type_menu, "_NET_WM_WINDOW_TYPE_MENU");
+    CREATE(net_wm_window_type_utility, "_NET_WM_WINDOW_TYPE_UTILITY");
+    CREATE(net_wm_window_type_splash, "_NET_WM_WINDOW_TYPE_SPLASH");
+    CREATE(net_wm_window_type_dialog, "_NET_WM_WINDOW_TYPE_DIALOG");
+    CREATE(net_wm_window_type_normal, "_NET_WM_WINDOW_TYPE_NORMAL");
+    CREATE(net_wm_window_type_popup_menu, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
+
+    prop_atoms.net_wm_moveresize_size_topleft = 0;
+    prop_atoms.net_wm_moveresize_size_top = 1;
+    prop_atoms.net_wm_moveresize_size_topright = 2;
+    prop_atoms.net_wm_moveresize_size_right = 3;
+    prop_atoms.net_wm_moveresize_size_bottomright = 4;
+    prop_atoms.net_wm_moveresize_size_bottom = 5;
+    prop_atoms.net_wm_moveresize_size_bottomleft = 6;
+    prop_atoms.net_wm_moveresize_size_left = 7;
+    prop_atoms.net_wm_moveresize_move = 8;
+    prop_atoms.net_wm_moveresize_size_keyboard = 9;
+    prop_atoms.net_wm_moveresize_move_keyboard = 10;
+    prop_atoms.net_wm_moveresize_cancel = 11;
+
+    CREATE(net_wm_action_move, "_NET_WM_ACTION_MOVE");
+    CREATE(net_wm_action_resize, "_NET_WM_ACTION_RESIZE");
+    CREATE(net_wm_action_minimize, "_NET_WM_ACTION_MINIMIZE");
+    CREATE(net_wm_action_shade, "_NET_WM_ACTION_SHADE");
+    CREATE(net_wm_action_maximize_horz, "_NET_WM_ACTION_MAXIMIZE_HORZ");
+    CREATE(net_wm_action_maximize_vert, "_NET_WM_ACTION_MAXIMIZE_VERT");
+    CREATE(net_wm_action_fullscreen, "_NET_WM_ACTION_FULLSCREEN");
+    CREATE(net_wm_action_change_desktop, "_NET_WM_ACTION_CHANGE_DESKTOP");
+    CREATE(net_wm_action_close, "_NET_WM_ACTION_CLOSE");
+    CREATE(net_wm_action_above, "_NET_WM_ACTION_ABOVE");
+    CREATE(net_wm_action_below, "_NET_WM_ACTION_BELOW");
+
+    CREATE(net_wm_state_modal, "_NET_WM_STATE_MODAL");
+/*    CREATE(net_wm_state_sticky, "_NET_WM_STATE_STICKY");*/
+    CREATE(net_wm_state_maximized_vert, "_NET_WM_STATE_MAXIMIZED_VERT");
+    CREATE(net_wm_state_maximized_horz, "_NET_WM_STATE_MAXIMIZED_HORZ");
+    CREATE(net_wm_state_shaded, "_NET_WM_STATE_SHADED");
+    CREATE(net_wm_state_skip_taskbar, "_NET_WM_STATE_SKIP_TASKBAR");
+    CREATE(net_wm_state_skip_pager, "_NET_WM_STATE_SKIP_PAGER");
+    CREATE(net_wm_state_hidden, "_NET_WM_STATE_HIDDEN");
+    CREATE(net_wm_state_fullscreen, "_NET_WM_STATE_FULLSCREEN");
+    CREATE(net_wm_state_above, "_NET_WM_STATE_ABOVE");
+    CREATE(net_wm_state_below, "_NET_WM_STATE_BELOW");
+    CREATE(net_wm_state_demands_attention, "_NET_WM_STATE_DEMANDS_ATTENTION");
+
+    prop_atoms.net_wm_state_add = 1;
+    prop_atoms.net_wm_state_remove = 0;
+    prop_atoms.net_wm_state_toggle = 2;
+
+    prop_atoms.net_wm_orientation_horz = 0;
+    prop_atoms.net_wm_orientation_vert = 1;
+    prop_atoms.net_wm_topleft = 0;
+    prop_atoms.net_wm_topright = 1;
+    prop_atoms.net_wm_bottomright = 2;
+    prop_atoms.net_wm_bottomleft = 3;
+
+    CREATE(kde_wm_change_state, "_KDE_WM_CHANGE_STATE");
+    CREATE(kde_net_wm_window_type_override,"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
+
+/*
+    CREATE(rootpmapid, "_XROOTPMAP_ID");
+    CREATE(esetrootid, "ESETROOT_PMAP_ID");
+*/
+
+    CREATE(openbox_pid, "_OPENBOX_PID");
+    CREATE(ob_theme, "_OB_THEME");
+    CREATE(ob_config_file, "_OB_CONFIG_FILE");
+    CREATE(ob_wm_action_undecorate, "_OB_WM_ACTION_UNDECORATE");
+    CREATE(ob_wm_state_undecorated, "_OB_WM_STATE_UNDECORATED");
+    CREATE(ob_control, "_OB_CONTROL");
+    CREATE(ob_version, "_OB_VERSION");
+    CREATE(ob_app_role, "_OB_APP_ROLE");
+    CREATE(ob_app_name, "_OB_APP_NAME");
+    CREATE(ob_app_class, "_OB_APP_CLASS");
+    CREATE(ob_app_type, "_OB_APP_TYPE");
+}
+
+#include <X11/Xutil.h>
+#include <glib.h>
+#include <string.h>
+
+/* this just isn't used... and it also breaks on 64bit, watch out
+static gboolean get(Window win, Atom prop, Atom type, gint size,
+                    guchar **data, gulong num)
+{
+    gboolean ret = FALSE;
+    gint res;
+    guchar *xdata = NULL;
+    Atom ret_type;
+    gint ret_size;
+    gulong ret_items, bytes_left;
+    glong num32 = 32 / size * num; /\* num in 32-bit elements *\/
+
+    res = XGetWindowProperty(display, win, prop, 0l, num32,
+                             FALSE, type, &ret_type, &ret_size,
+                             &ret_items, &bytes_left, &xdata);
+    if (res == Success && ret_items && xdata) {
+        if (ret_size == size && ret_items >= num) {
+            *data = g_memdup(xdata, num * (size / 8));
+            ret = TRUE;
+        }
+        XFree(xdata);
+    }
+    return ret;
+}
+*/
+
+static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
+                             guchar *data, gulong num)
+{
+    gboolean ret = FALSE;
+    gint res;
+    guchar *xdata = NULL;
+    Atom ret_type;
+    gint ret_size;
+    gulong ret_items, bytes_left;
+    glong num32 = 32 / size * num; /* num in 32-bit elements */
+
+    res = XGetWindowProperty(ob_display, win, prop, 0l, num32,
+                             FALSE, type, &ret_type, &ret_size,
+                             &ret_items, &bytes_left, &xdata);
+    if (res == Success && ret_items && xdata) {
+        if (ret_size == size && ret_items >= num) {
+            guint i;
+            for (i = 0; i < num; ++i)
+                switch (size) {
+                case 8:
+                    data[i] = xdata[i];
+                    break;
+                case 16:
+                    ((guint16*)data)[i] = ((gushort*)xdata)[i];
+                    break;
+                case 32:
+                    ((guint32*)data)[i] = ((gulong*)xdata)[i];
+                    break;
+                default:
+                    g_assert_not_reached(); /* unhandled size */
+                }
+            ret = TRUE;
+        }
+        XFree(xdata);
+    }
+    return ret;
+}
+
+static gboolean get_all(Window win, Atom prop, Atom type, gint size,
+                        guchar **data, guint *num)
+{
+    gboolean ret = FALSE;
+    gint res;
+    guchar *xdata = NULL;
+    Atom ret_type;
+    gint ret_size;
+    gulong ret_items, bytes_left;
+
+    res = XGetWindowProperty(ob_display, win, prop, 0l, G_MAXLONG,
+                             FALSE, type, &ret_type, &ret_size,
+                             &ret_items, &bytes_left, &xdata);
+    if (res == Success) {
+        if (ret_size == size && ret_items > 0) {
+            guint i;
+
+            *data = g_malloc(ret_items * (size / 8));
+            for (i = 0; i < ret_items; ++i)
+                switch (size) {
+                case 8:
+                    (*data)[i] = xdata[i];
+                    break;
+                case 16:
+                    ((guint16*)*data)[i] = ((gushort*)xdata)[i];
+                    break;
+                case 32:
+                    ((guint32*)*data)[i] = ((gulong*)xdata)[i];
+                    break;
+                default:
+                    g_assert_not_reached(); /* unhandled size */
+                }
+            *num = ret_items;
+            ret = TRUE;
+        }
+        XFree(xdata);
+    }
+    return ret;
+}
+
+static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr)
+{
+    XTextProperty tprop;
+    gboolean ret = FALSE;
+
+    if (XGetTextProperty(ob_display, win, &tprop, prop) && tprop.nitems) {
+        if (XTextPropertyToStringList(&tprop, list, nstr))
+            ret = TRUE;
+        XFree(tprop.value);
+    }
+    return ret;
+}
+
+gboolean prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
+{
+    return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
+}
+
+gboolean prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+                          guint *nret)
+{
+    return get_all(win, prop, type, 32, (guchar**)ret, nret);
+}
+
+gboolean prop_get_string_locale(Window win, Atom prop, gchar **ret)
+{
+    gchar **list;
+    gint nstr;
+    gchar *s;
+
+    if (get_stringlist(win, prop, &list, &nstr) && nstr) {
+        s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
+        XFreeStringList(list);
+        if (s) {
+            *ret = s;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+gboolean prop_get_strings_locale(Window win, Atom prop, gchar ***ret)
+{
+    GSList *strs = NULL, *it;
+    gchar *raw, *p;
+    guint num, i, count = 0;
+
+    if (get_all(win, prop, prop_atoms.string, 8, (guchar**)&raw, &num)) {
+
+        p = raw;
+        while (p < raw + num) {
+            ++count;
+            strs = g_slist_append(strs, p);
+            p += strlen(p) + 1; /* next string */
+        }
+
+        *ret = g_new0(gchar*, count + 1);
+        (*ret)[count] = NULL; /* null terminated list */
+
+        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+            (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
+            /* make sure translation did not fail */
+            if (!(*ret)[i])
+                (*ret)[i] = g_strdup("");
+        }
+        g_free(raw);
+        g_slist_free(strs);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+gboolean prop_get_string_utf8(Window win, Atom prop, gchar **ret)
+{
+    gchar *raw;
+    gchar *str;
+    guint num;
+
+    if (get_all(win, prop, prop_atoms.utf8, 8, (guchar**)&raw, &num)) {
+        str = g_strndup(raw, num); /* grab the first string from the list */
+        g_free(raw);
+        if (g_utf8_validate(str, -1, NULL)) {
+            *ret = str;
+            return TRUE;
+        }
+        g_free(str);
+    }
+    return FALSE;
+}
+
+gboolean prop_get_strings_utf8(Window win, Atom prop, gchar ***ret)
+{
+    GSList *strs = NULL, *it;
+    gchar *raw, *p;
+    guint num, i, count = 0;
+
+    if (get_all(win, prop, prop_atoms.utf8, 8, (guchar**)&raw, &num)) {
+
+        p = raw;
+        while (p < raw + num) {
+            ++count;
+            strs = g_slist_append(strs, p);
+            p += strlen(p) + 1; /* next string */
+        }
+
+        *ret = g_new0(gchar*, count + 1);
+
+        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+            if (g_utf8_validate(it->data, -1, NULL))
+                (*ret)[i] = g_strdup(it->data);
+            else
+                (*ret)[i] = g_strdup("");
+        }
+        g_free(raw);
+        g_slist_free(strs);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void prop_set32(Window win, Atom prop, Atom type, gulong val)
+{
+    XChangeProperty(ob_display, win, prop, type, 32, PropModeReplace,
+                    (guchar*)&val, 1);
+}
+
+void prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+                      guint num)
+{
+    XChangeProperty(ob_display, win, prop, type, 32, PropModeReplace,
+                    (guchar*)val, num);
+}
+
+void prop_set_string_utf8(Window win, Atom prop, const gchar *val)
+{
+    XChangeProperty(ob_display, win, prop, prop_atoms.utf8, 8,
+                    PropModeReplace, (const guchar*)val, strlen(val));
+}
+
+void prop_set_strings_utf8(Window win, Atom prop, gchar **strs)
+{
+    GString *str;
+    gchar **s;
+
+    str = g_string_sized_new(0);
+    for (s = strs; *s; ++s) {
+        str = g_string_append(str, *s);
+        str = g_string_append_c(str, '\0');
+    }
+    XChangeProperty(ob_display, win, prop, prop_atoms.utf8, 8,
+                    PropModeReplace, (guchar*)str->str, str->len);
+    g_string_free(str, TRUE);
+}
+
+void prop_erase(Window win, Atom prop)
+{
+    XDeleteProperty(ob_display, win, prop);
+}
+
+void prop_message(Window about, Atom messagetype, glong data0, glong data1,
+                  glong data2, glong data3, glong mask)
+{
+    prop_message_to(RootWindow(ob_display, ob_screen), about, messagetype,
+                    data0, data1, data2, data3, 0, mask);
+}
+
+void prop_message_to(Window to, Window about, Atom messagetype,
+                     glong data0, glong data1, glong data2,
+                     glong data3, glong data4, glong mask)
+{
+    XEvent ce;
+    ce.xclient.type = ClientMessage;
+    ce.xclient.message_type = messagetype;
+    ce.xclient.display = ob_display;
+    ce.xclient.window = about;
+    ce.xclient.format = 32;
+    ce.xclient.data.l[0] = data0;
+    ce.xclient.data.l[1] = data1;
+    ce.xclient.data.l[2] = data2;
+    ce.xclient.data.l[3] = data3;
+    ce.xclient.data.l[4] = data4;
+    XSendEvent(ob_display, to, FALSE, mask, &ce);
+}
diff --git a/openbox/prop.h b/openbox/prop.h
new file mode 100644 (file)
index 0000000..7164567
--- /dev/null
@@ -0,0 +1,267 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   prop.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __atoms_h
+#define __atoms_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+
+/*! The atoms on the X server which this class will cache */
+typedef struct Atoms {
+    /* types */
+    Atom cardinal; /*!< The atom which represents the Cardinal data type */
+    Atom window;   /*!< The atom which represents window ids */
+    Atom pixmap;   /*!< The atom which represents pixmap ids */
+    Atom atom;     /*!< The atom which represents atom values */
+    Atom string;   /*!< The atom which represents ascii strings */
+    Atom utf8;     /*!< The atom which represents utf8-encoded strings */
+
+    /* selection stuff */
+    Atom manager;
+
+    /* window hints */
+    Atom wm_colormap_windows;
+    Atom wm_protocols;
+    Atom wm_state;
+    Atom wm_delete_window;
+    Atom wm_take_focus;
+    Atom wm_change_state;
+    Atom wm_name;
+    Atom wm_icon_name;
+    Atom wm_class;
+    Atom wm_window_role;
+    Atom wm_client_machine;
+    Atom wm_command;
+    Atom wm_client_leader;
+    Atom wm_transient_for;
+    Atom motif_wm_hints;
+    Atom motif_wm_info;
+
+    /* SM atoms */
+    Atom sm_client_id;
+
+    /* NETWM atoms */
+
+    /* Atoms that are used inside messages - these don't go in net_supported */
+
+    Atom net_wm_moveresize_size_topleft;
+    Atom net_wm_moveresize_size_top;
+    Atom net_wm_moveresize_size_topright;
+    Atom net_wm_moveresize_size_right;
+    Atom net_wm_moveresize_size_bottomright;
+    Atom net_wm_moveresize_size_bottom;
+    Atom net_wm_moveresize_size_bottomleft;
+    Atom net_wm_moveresize_size_left;
+    Atom net_wm_moveresize_move;
+    Atom net_wm_moveresize_size_keyboard;
+    Atom net_wm_moveresize_move_keyboard;
+    Atom net_wm_moveresize_cancel;
+
+    Atom net_wm_state_add;
+    Atom net_wm_state_remove;
+    Atom net_wm_state_toggle;
+
+    Atom net_wm_orientation_horz;
+    Atom net_wm_orientation_vert;
+    Atom net_wm_topleft;
+    Atom net_wm_topright;
+    Atom net_wm_bottomright;
+    Atom net_wm_bottomleft;
+
+    /* types that we use but don't support */
+
+    Atom net_wm_window_type_popup_menu;
+
+    /* Everything below here must go in net_supported on the root window */
+
+    /* root window properties */
+    Atom net_supported;
+    Atom net_client_list;
+    Atom net_client_list_stacking;
+    Atom net_number_of_desktops;
+    Atom net_desktop_geometry;
+    Atom net_desktop_viewport;
+    Atom net_current_desktop;
+    Atom net_desktop_names;
+    Atom net_active_window;
+/*    Atom net_restack_window;*/
+    Atom net_workarea;
+    Atom net_supporting_wm_check;
+    Atom net_desktop_layout;
+    Atom net_showing_desktop;
+
+    /* root window messages */
+    Atom net_close_window;
+    Atom net_wm_moveresize;
+    Atom net_moveresize_window;
+    Atom net_request_frame_extents;
+    Atom net_restack_window;
+
+    /* helpful hints to apps that aren't used for anything */
+    Atom net_wm_full_placement;
+
+    /* startup-notification extension */
+    Atom net_startup_id;
+
+    /* application window properties */
+    Atom net_wm_name;
+    Atom net_wm_visible_name;
+    Atom net_wm_icon_name;
+    Atom net_wm_visible_icon_name;
+    Atom net_wm_desktop;
+    Atom net_wm_window_type;
+    Atom net_wm_state;
+    Atom net_wm_strut;
+    Atom net_wm_strut_partial;
+    Atom net_wm_icon;
+    Atom net_wm_icon_geometry;
+    Atom net_wm_pid;
+    Atom net_wm_allowed_actions;
+    Atom net_wm_user_time;
+/*  Atom net_wm_user_time_window; */
+    Atom net_frame_extents;
+
+    /* application protocols */
+    Atom net_wm_ping;
+#ifdef SYNC
+    Atom net_wm_sync_request;
+    Atom net_wm_sync_request_counter;
+#endif
+
+    Atom net_wm_window_type_desktop;
+    Atom net_wm_window_type_dock;
+    Atom net_wm_window_type_toolbar;
+    Atom net_wm_window_type_menu;
+    Atom net_wm_window_type_utility;
+    Atom net_wm_window_type_splash;
+    Atom net_wm_window_type_dialog;
+    Atom net_wm_window_type_normal;
+
+    Atom net_wm_action_move;
+    Atom net_wm_action_resize;
+    Atom net_wm_action_minimize;
+    Atom net_wm_action_shade;
+/*    Atom net_wm_action_stick;*/
+    Atom net_wm_action_maximize_horz;
+    Atom net_wm_action_maximize_vert;
+    Atom net_wm_action_fullscreen;
+    Atom net_wm_action_change_desktop;
+    Atom net_wm_action_close;
+    Atom net_wm_action_above;
+    Atom net_wm_action_below;
+
+    Atom net_wm_state_modal;
+/*    Atom net_wm_state_sticky;*/
+    Atom net_wm_state_maximized_vert;
+    Atom net_wm_state_maximized_horz;
+    Atom net_wm_state_shaded;
+    Atom net_wm_state_skip_taskbar;
+    Atom net_wm_state_skip_pager;
+    Atom net_wm_state_hidden;
+    Atom net_wm_state_fullscreen;
+    Atom net_wm_state_above;
+    Atom net_wm_state_below;
+    Atom net_wm_state_demands_attention;
+
+    /* KDE atoms */
+
+    Atom kde_wm_change_state;
+    Atom kde_net_wm_frame_strut;
+    Atom kde_net_wm_window_type_override;
+
+/*
+    Atom rootpmapid;
+    Atom esetrootid;
+*/
+
+    /* Openbox specific atoms */
+
+    Atom ob_wm_action_undecorate;
+    Atom ob_wm_state_undecorated;
+    Atom openbox_pid; /* this is depreecated in favour of ob_control */
+    Atom ob_theme;
+    Atom ob_config_file;
+    Atom ob_control;
+    Atom ob_version;
+    Atom ob_app_role;
+    Atom ob_app_name;
+    Atom ob_app_class;
+    Atom ob_app_type;
+} Atoms;
+extern Atoms prop_atoms;
+
+void prop_startup();
+
+gboolean prop_get32(Window win, Atom prop, Atom type, guint32 *ret);
+gboolean prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+                          guint *nret);
+gboolean prop_get_string_locale(Window win, Atom prop, gchar **ret);
+gboolean prop_get_string_utf8(Window win, Atom prop, gchar **ret);
+gboolean prop_get_strings_locale(Window win, Atom prop, gchar ***ret);
+gboolean prop_get_strings_utf8(Window win, Atom prop, gchar ***ret);
+
+void prop_set32(Window win, Atom prop, Atom type, gulong val);
+void prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+                      guint num);
+void prop_set_string_utf8(Window win, Atom prop, const gchar *val);
+void prop_set_strings_utf8(Window win, Atom prop, gchar **strs);
+
+void prop_erase(Window win, Atom prop);
+
+void prop_message(Window about, Atom messagetype, glong data0, glong data1,
+                  glong data2, glong data3, glong mask);
+void prop_message_to(Window to, Window about, Atom messagetype,
+                     glong data0, glong data1, glong data2,
+                     glong data3, glong data4, glong mask);
+
+#define PROP_GET32(win, prop, type, ret) \
+    (prop_get32(win, prop_atoms.prop, prop_atoms.type, ret))
+#define PROP_GETA32(win, prop, type, ret, nret) \
+    (prop_get_array32(win, prop_atoms.prop, prop_atoms.type, ret, \
+                      nret))
+#define PROP_GETS(win, prop, type, ret) \
+    (prop_get_string_##type(win, prop_atoms.prop, ret))
+#define PROP_GETSS(win, prop, type, ret) \
+    (prop_get_strings_##type(win, prop_atoms.prop, ret))
+
+#define PROP_SET32(win, prop, type, val) \
+    prop_set32(win, prop_atoms.prop, prop_atoms.type, val)
+#define PROP_SETA32(win, prop, type, val, num) \
+    prop_set_array32(win, prop_atoms.prop, prop_atoms.type, val, num)
+#define PROP_SETS(win, prop, val) \
+    prop_set_string_utf8(win, prop_atoms.prop, val)
+#define PROP_SETSS(win, prop, strs) \
+    prop_set_strings_utf8(win, prop_atoms.prop, strs)
+
+#define PROP_ERASE(win, prop) prop_erase(win, prop_atoms.prop)
+
+#define PROP_MSG(about, msgtype, data0, data1, data2, data3) \
+  (prop_message(about, prop_atoms.msgtype, data0, data1, data2, data3, \
+                SubstructureNotifyMask | SubstructureRedirectMask))
+
+#define PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, data4, \
+                    mask) \
+    (prop_message_to(to, about, prop_atoms.msgtype,                        \
+                     data0, data1, data2, data3, data4, mask))
+
+#endif
index bce2faa..2e69f11 100644 (file)
@@ -32,6 +32,7 @@
 #include "focus.h"
 #include "focus_cycle.h"
 #include "popup.h"
+#include "version.h"
 #include "obrender/render.h"
 #include "gettext.h"
 #include "obt/display.h"
@@ -294,15 +295,20 @@ gboolean screen_annex(void)
     supported[i++] = OBT_PROP_ATOM(OB_THEME);
     supported[i++] = OBT_PROP_ATOM(OB_CONFIG_FILE);
     supported[i++] = OBT_PROP_ATOM(OB_CONTROL);
-    supported[i++] = OBT_PROP_ATOM(OB_ROLE);
-    supported[i++] = OBT_PROP_ATOM(OB_NAME);
-    supported[i++] = OBT_PROP_ATOM(OB_CLASS);
+    supported[i++] = OBT_PROP_ATOM(OB_VERSION);
+    supported[i++] = OBT_PROP_ATOM(OB_APP_ROLE);
+    supported[i++] = OBT_PROP_ATOM(OB_APP_NAME);
+    supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS);
+    supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE);
     g_assert(i == num_support);
 
     OBT_PROP_SETA32(obt_root(ob_screen),
                     NET_SUPPORTED, ATOM, supported, num_support);
     g_free(supported);
 
+    OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION, utf8,
+                  OPENBOX_VERSION);
+
     screen_tell_ksplash();
 
     return TRUE;
@@ -705,9 +711,6 @@ void screen_set_desktop(guint num, gboolean dofocus)
         if (WINDOW_IS_CLIENT(it->data)) {
             ObClient *c = it->data;
             if (client_hide(c)) {
-                /* in the middle of cycling..? kill it. */
-                focus_cycle_stop(c);
-
                 if (c == focus_client) {
                     /* c was focused and we didn't do fallback clearly so make
                        sure openbox doesnt still consider the window focused.
@@ -723,6 +726,8 @@ void screen_set_desktop(guint num, gboolean dofocus)
         }
     }
 
+    focus_cycle_addremove(NULL, TRUE);
+
     event_end_ignore_all_enters(ignore_start);
 
     if (event_curtime != CurrentTime)
diff --git a/parser/parse.c b/parser/parse.c
new file mode 100644 (file)
index 0000000..897d738
--- /dev/null
@@ -0,0 +1,532 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   parse.c for the Openbox window manager
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "parse.h"
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static gboolean xdg_start;
+static gchar   *xdg_config_home_path;
+static gchar   *xdg_data_home_path;
+static GSList  *xdg_config_dir_paths;
+static GSList  *xdg_data_dir_paths;
+
+struct Callback {
+    gchar *tag;
+    ParseCallback func;
+    gpointer data;
+};
+
+struct _ObParseInst {
+    GHashTable *callbacks;
+};
+
+static void destfunc(struct Callback *c)
+{
+    g_free(c->tag);
+    g_free(c);
+}
+
+ObParseInst* parse_startup(void)
+{
+    ObParseInst *i = g_new(ObParseInst, 1);
+    i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+                                         (GDestroyNotify)destfunc);
+    return i;
+}
+
+void parse_shutdown(ObParseInst *i)
+{
+    if (i) {
+        g_hash_table_destroy(i->callbacks);
+        g_free(i);
+    }
+}
+
+void parse_register(ObParseInst *i, const gchar *tag,
+                    ParseCallback func, gpointer data)
+{
+    struct Callback *c;
+
+    if ((c = g_hash_table_lookup(i->callbacks, tag))) {
+        g_error("Tag '%s' already registered", tag);
+        return;
+    }
+
+    c = g_new(struct Callback, 1);
+    c->tag = g_strdup(tag);
+    c->func = func;
+    c->data = data;
+    g_hash_table_insert(i->callbacks, c->tag, c);
+}
+
+gboolean parse_load_rc(const gchar *file, xmlDocPtr *doc, xmlNodePtr *root)
+{
+    GSList *it;
+    gboolean r = FALSE;
+
+    if (file && parse_load(file, "openbox_config", doc, root))
+        return TRUE;
+
+    for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
+        gchar *path;
+
+        path = g_build_filename(it->data, "openbox", "rc.xml", NULL);
+        r = parse_load(path, "openbox_config", doc, root);
+        g_free(path);
+    }
+
+    return r;
+}
+
+gboolean parse_load_theme(const gchar *name, xmlDocPtr *doc, xmlNodePtr *root,
+                          gchar **retpath)
+{
+    GSList *it;
+    gchar *path;
+    gboolean r = FALSE;
+    gchar *eng;
+
+    /* backward compatibility.. */
+    path = g_build_filename(g_get_home_dir(), ".themes", name,
+                            "openbox-3", "themerc.xml", NULL);
+    if (parse_load(path, "openbox_theme", doc, root) &&
+        parse_attr_string("engine", *root, &eng))
+    {
+        if (!strcmp(eng, "box")) {
+            *retpath = g_path_get_dirname(path);
+            r = TRUE;
+        }
+        g_free(eng);
+    }
+    g_free(path);
+
+    if (!r) {
+        for (it = xdg_data_dir_paths; !r && it; it = g_slist_next(it)) {
+            path = g_build_filename(it->data, "themes", name, "openbox-3",
+                                    "themerc.xml", NULL);
+            if (parse_load(path, "openbox_theme", doc, root) &&
+                parse_attr_string("engine", *root, &eng))
+            {
+                if (!strcmp(eng, "box")) {
+                    *retpath = g_path_get_dirname(path);
+                    r = TRUE;
+                }
+                g_free(eng);
+            }
+            g_free(path);
+        }
+    }
+    return r;
+}
+
+gboolean parse_load_menu(const gchar *file, xmlDocPtr *doc, xmlNodePtr *root)
+{
+    GSList *it;
+    gchar *path;
+    gboolean r = FALSE;
+
+    if (file[0] == '/') {
+        r = parse_load(file, "openbox_menu", doc, root);
+    } else {
+        for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
+            path = g_build_filename(it->data, "openbox", file, NULL);
+            r = parse_load(path, "openbox_menu", doc, root);
+            g_free(path);
+        }
+    }
+    return r;
+}
+
+gboolean parse_load(const gchar *path, const gchar *rootname,
+                    xmlDocPtr *doc, xmlNodePtr *root)
+{
+    struct stat s;
+
+    if (stat(path, &s) < 0)
+        return FALSE;
+
+    /* XML_PARSE_BLANKS is needed apparently. When it loads a theme file,
+       without this option, the tree is weird and has extra nodes in it. */
+    if ((*doc = xmlReadFile(path, NULL,
+                            XML_PARSE_NOBLANKS | XML_PARSE_RECOVER))) {
+        *root = xmlDocGetRootElement(*doc);
+        if (!*root) {
+            xmlFreeDoc(*doc);
+            *doc = NULL;
+            g_message("%s is an empty document", path);
+        } else {
+            if (xmlStrcmp((*root)->name, (const xmlChar*)rootname)) {
+                xmlFreeDoc(*doc);
+                *doc = NULL;
+                g_message("XML Document %s is of wrong type. Root "
+                          "node is not '%s'", path, rootname);
+            }
+        }
+    }
+    if (!*doc)
+        return FALSE;
+    return TRUE;
+}
+
+gboolean parse_load_mem(gpointer data, guint len, const gchar *rootname,
+                        xmlDocPtr *doc, xmlNodePtr *root)
+{
+    if ((*doc = xmlParseMemory(data, len))) {
+        *root = xmlDocGetRootElement(*doc);
+        if (!*root) {
+            xmlFreeDoc(*doc);
+            *doc = NULL;
+            g_message("Given memory is an empty document");
+        } else {
+            if (xmlStrcmp((*root)->name, (const xmlChar*)rootname)) {
+                xmlFreeDoc(*doc);
+                *doc = NULL;
+                g_message("XML Document in given memory is of wrong "
+                          "type. Root node is not '%s'\n", rootname);
+            }
+        }
+    }
+    if (!*doc)
+        return FALSE;
+    return TRUE;
+}
+
+void parse_close(xmlDocPtr doc)
+{
+    xmlFreeDoc(doc);
+}
+
+void parse_tree(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+{
+    while (node) {
+        struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
+
+        if (c)
+            c->func(i, doc, node, c->data);
+
+        node = node->next;
+    }
+}
+
+gchar *parse_string(xmlDocPtr doc, xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
+    gchar *s = g_strdup(c ? (gchar*)c : "");
+    xmlFree(c);
+    return s;
+}
+
+gint parse_int(xmlDocPtr doc, xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
+    gint i = c ? atoi((gchar*)c) : 0;
+    xmlFree(c);
+    return i;
+}
+
+gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
+    gboolean b = FALSE;
+    if (c && !xmlStrcasecmp(c, (const xmlChar*) "true"))
+        b = TRUE;
+    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "yes"))
+        b = TRUE;
+    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "on"))
+        b = TRUE;
+    xmlFree(c);
+    return b;
+}
+
+gboolean parse_contains(const gchar *val, xmlDocPtr doc, xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
+    gboolean r;
+    r = !xmlStrcasecmp(c, (const xmlChar*) val);
+    xmlFree(c);
+    return r;
+}
+
+xmlNodePtr parse_find_node(const gchar *tag, xmlNodePtr node)
+{
+    while (node) {
+        if (!xmlStrcmp(node->name, (const xmlChar*) tag))
+            return node;
+        node = node->next;
+    }
+    return NULL;
+}
+
+gboolean parse_attr_bool(const gchar *name, xmlNodePtr node, gboolean *value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "false"))
+            *value = FALSE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "no"))
+            *value = FALSE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "off"))
+            *value = FALSE, r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean parse_attr_int(const gchar *name, xmlNodePtr node, gint *value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        *value = atoi((gchar*)c);
+        r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean parse_attr_string(const gchar *name, xmlNodePtr node, gchar **value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        *value = g_strdup((gchar*)c);
+        r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean parse_attr_contains(const gchar *val, xmlNodePtr node,
+                             const gchar *name)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c)
+        r = !xmlStrcasecmp(c, (const xmlChar*) val);
+    xmlFree(c);
+    return r;
+}
+
+static gint slist_path_cmp(const gchar *a, const gchar *b)
+{
+    return strcmp(a, b);
+}
+
+typedef GSList* (*GSListFunc) (gpointer list, gconstpointer data);
+
+static GSList* slist_path_add(GSList *list, gpointer data, GSListFunc func)
+{
+    g_assert(func);
+
+    if (!data)
+        return list;
+
+    if (!g_slist_find_custom(list, data, (GCompareFunc) slist_path_cmp))
+        list = func(list, data);
+    else
+        g_free(data);
+
+    return list;
+}
+
+static GSList* split_paths(const gchar *paths)
+{
+    GSList *list = NULL;
+    gchar **spl, **it;
+
+    if (!paths)
+        return NULL;
+    spl = g_strsplit(paths, ":", -1);
+    for (it = spl; *it; ++it)
+        list = slist_path_add(list, *it, (GSListFunc) g_slist_append);
+    g_free(spl);
+    return list;
+}
+
+void parse_paths_startup(void)
+{
+    const gchar *path;
+
+    if (xdg_start)
+        return;
+    xdg_start = TRUE;
+
+    path = g_getenv("XDG_CONFIG_HOME");
+    if (path && path[0] != '\0') /* not unset or empty */
+        xdg_config_home_path = g_build_filename(path, NULL);
+    else
+        xdg_config_home_path = g_build_filename(g_get_home_dir(), ".config",
+                                                NULL);
+
+    path = g_getenv("XDG_DATA_HOME");
+    if (path && path[0] != '\0') /* not unset or empty */
+        xdg_data_home_path = g_build_filename(path, NULL);
+    else
+        xdg_data_home_path = g_build_filename(g_get_home_dir(), ".local",
+                                              "share", NULL);
+
+    path = g_getenv("XDG_CONFIG_DIRS");
+    if (path && path[0] != '\0') /* not unset or empty */
+        xdg_config_dir_paths = split_paths(path);
+    else {
+        xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
+                                              g_strdup(CONFIGDIR),
+                                              (GSListFunc) g_slist_append);
+        xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
+                                              g_build_filename
+                                              (G_DIR_SEPARATOR_S,
+                                               "etc", "xdg", NULL),
+                                              (GSListFunc) g_slist_append);
+    }
+    xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
+                                          g_strdup(xdg_config_home_path),
+                                          (GSListFunc) g_slist_prepend);
+
+    path = g_getenv("XDG_DATA_DIRS");
+    if (path && path[0] != '\0') /* not unset or empty */
+        xdg_data_dir_paths = split_paths(path);
+    else {
+        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
+                                            g_strdup(DATADIR),
+                                            (GSListFunc) g_slist_append);
+        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
+                                            g_build_filename
+                                            (G_DIR_SEPARATOR_S,
+                                             "usr", "local", "share", NULL),
+                                            (GSListFunc) g_slist_append);
+        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
+                                            g_build_filename
+                                            (G_DIR_SEPARATOR_S,
+                                             "usr", "share", NULL),
+                                            (GSListFunc) g_slist_append);
+    }
+    xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
+                                        g_strdup(xdg_data_home_path),
+                                        (GSListFunc) g_slist_prepend);
+}
+
+void parse_paths_shutdown(void)
+{
+    GSList *it;
+
+    if (!xdg_start)
+        return;
+    xdg_start = FALSE;
+
+    for (it = xdg_config_dir_paths; it; it = g_slist_next(it))
+        g_free(it->data);
+    g_slist_free(xdg_config_dir_paths);
+    xdg_config_dir_paths = NULL;
+    for (it = xdg_data_dir_paths; it; it = g_slist_next(it))
+        g_free(it->data);
+    g_slist_free(xdg_data_dir_paths);
+    xdg_data_dir_paths = NULL;
+    g_free(xdg_config_home_path);
+    xdg_config_home_path = NULL;
+    g_free(xdg_data_home_path);
+    xdg_data_home_path = NULL;
+}
+
+gchar *parse_expand_tilde(const gchar *f)
+{
+    gchar *ret;
+    GRegex *regex;
+
+    if (!f)
+        return NULL;
+
+    regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
+                        G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
+    ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
+    g_regex_unref(regex);
+
+    return ret;
+}
+
+gboolean parse_mkdir(const gchar *path, gint mode)
+{
+    gboolean ret = TRUE;
+
+    g_return_val_if_fail(path != NULL, FALSE);
+    g_return_val_if_fail(path[0] != '\0', FALSE);
+
+    if (!g_file_test(path, G_FILE_TEST_IS_DIR))
+        if (mkdir(path, mode) == -1)
+            ret = FALSE;
+
+    return ret;
+}
+
+gboolean parse_mkdir_path(const gchar *path, gint mode)
+{
+    gboolean ret = TRUE;
+
+    g_return_val_if_fail(path != NULL, FALSE);
+    g_return_val_if_fail(path[0] == '/', FALSE);
+
+    if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
+        gchar *c, *e;
+
+        c = g_strdup(path);
+        e = c;
+        while ((e = strchr(e + 1, '/'))) {
+            *e = '\0';
+            if (!(ret = parse_mkdir(c, mode)))
+                goto parse_mkdir_path_end;
+            *e = '/';
+        }
+        ret = parse_mkdir(c, mode);
+
+    parse_mkdir_path_end:
+        g_free(c);
+    }
+
+    return ret;
+}
+
+const gchar* parse_xdg_config_home_path(void)
+{
+    return xdg_config_home_path;
+}
+
+const gchar* parse_xdg_data_home_path(void)
+{
+    return xdg_data_home_path;
+}
+
+GSList* parse_xdg_config_dir_paths(void)
+{
+    return xdg_config_dir_paths;
+}
+
+GSList* parse_xdg_data_dir_paths(void)
+{
+    return xdg_data_dir_paths;
+}
index ffa5201..d970bf3 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -1,15 +1,16 @@
-# Hungarian messages for openbox.
-# Copyright (C) 2007 Mikael Magnusson
+# Hungarian translation of openbox.
+# Copyright (C) 2007 Dana Jansens
 # This file is distributed under the same license as the openbox package.
 # Robert Kuszinger <hiding@freemail.hu>, 2007.
+# Laszlo Dvornik <dvornik@gnome.hu>, 2010.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: Openbox 3.4.7\n"
+"Project-Id-Version: openbox 3.4.10\n"
 "Report-Msgid-Bugs-To: http://bugzilla.icculus.org\n"
-"POT-Creation-Date: 2008-11-15 22:28+0100\n"
-"PO-Revision-Date: 2008-03-17 19:25+0100\n"
-"Last-Translator: Robert Kuszinger <hiding@freemail.hu>\n"
+"POT-Creation-Date: 2010-01-08 22:39+0100\n"
+"PO-Revision-Date: 2010-01-08 22:23+0100\n"
+"Last-Translator: Laszlo Dvornik <dvornik@gnome.hu>\n"
 "Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -19,7 +20,7 @@ msgstr ""
 #: openbox/actions.c:149
 #, c-format
 msgid "Invalid action \"%s\" requested. No such action exists."
-msgstr "Érvénytelen művelet \"%s\". Nem létezik ilyen."
+msgstr "Érvénytelen művelet \"%s\". Nem létezik ilyen művelet."
 
 #: openbox/actions/execute.c:128
 msgid "No"
@@ -38,54 +39,43 @@ msgstr "Végrehajtás"
 msgid "Failed to convert the path \"%s\" from utf8"
 msgstr "Az útvonalat nem sikerült átalakítani utf8-ból: \"%s\""
 
-#: openbox/actions/exit.c:52 openbox/actions/session.c:64
-#: openbox/client.c:3465
+#: openbox/actions/exit.c:62 openbox/client.c:3474
 msgid "Cancel"
 msgstr "Mégsem"
 
-#: openbox/actions/exit.c:53
+#: openbox/actions/exit.c:63
 msgid "Exit"
 msgstr "Kilépés"
 
-#: openbox/actions/exit.c:56
-msgid "Are you sure you want to exit Openbox?"
-msgstr "Biztos, hogy ki akarsz lépni az Openboxból?"
-
-#: openbox/actions/exit.c:57
-msgid "Exit Openbox"
-msgstr "Kilépés az Openboxból"
-
-#. TRANSLATORS: Don't translate the word "SessionLogout" as it's the
-#. name of the action you write in rc.xml
-#: openbox/actions/session.c:43
-msgid ""
-"The SessionLogout action is not available since Openbox was built without "
-"session management support"
-msgstr ""
-"A SessionLogout művelet nem elérhető mivel az Openbox szekciókezelés "
-"támogatása nélkül lett lefordítva"
+#: openbox/actions/exit.c:67
+msgid "Are you sure you want to log out?"
+msgstr "Biztos, hogy ki akarsz jelentkezni?"
 
-#: openbox/actions/session.c:65 openbox/actions/session.c:70
+#: openbox/actions/exit.c:68
 msgid "Log Out"
 msgstr "Kijelentkezés"
 
-#: openbox/actions/session.c:69
-msgid "Are you sure you want to log out?"
-msgstr "Biztos, hogy ki akarsz jelentkezni?"
+#: openbox/actions/exit.c:71
+msgid "Are you sure you want to exit Openbox?"
+msgstr "Biztos ki akar lépni az Openboxból?"
 
-#: openbox/client.c:2012
+#: openbox/actions/exit.c:72
+msgid "Exit Openbox"
+msgstr "Kilépés az Openboxból"
+
+#: openbox/client.c:2016
 msgid "Unnamed Window"
-msgstr "Névtelen Ablak"
+msgstr "Névtelen ablak"
 
-#: openbox/client.c:2026 openbox/client.c:2058
+#: openbox/client.c:2030 openbox/client.c:2062
 msgid "Killing..."
 msgstr "Kilövés..."
 
-#: openbox/client.c:2028 openbox/client.c:2060
+#: openbox/client.c:2032 openbox/client.c:2064
 msgid "Not Responding"
-msgstr "Nem Válaszol"
+msgstr "Nem válaszol"
 
-#: openbox/client.c:3454
+#: openbox/client.c:3463
 #, c-format
 msgid ""
 "The window \"%s\" does not seem to be responding.  Do you want to force it "
@@ -93,24 +83,24 @@ msgid ""
 msgstr ""
 "A(z) \"%s\" ablak nem válaszol. Erőltessük a kilépést a %s jelzés küldésével?"
 
-#: openbox/client.c:3456
+#: openbox/client.c:3465
 msgid "End Process"
-msgstr "Folyamat Vége"
+msgstr "Folyamat vége"
 
-#: openbox/client.c:3460
+#: openbox/client.c:3469
 #, c-format
 msgid ""
 "The window \"%s\" does not seem to be responding.  Do you want to disconnect "
 "it from the X server?"
-msgstr "A(z) \"%s\" ablak nem válaszol. Lekapcsoljuk az X szerverről?"
+msgstr "A(z) \"%s\" ablak nem válaszol. Lekapcsoljuk az X kiszolgálóról?"
 
-#: openbox/client.c:3462
+#: openbox/client.c:3471
 msgid "Disconnect"
-msgstr "Szétkapcsolódás"
+msgstr "Lekapcsolódás"
 
 #: openbox/client_list_combined_menu.c:87 openbox/client_list_menu.c:91
 msgid "Go there..."
-msgstr "Menjünk oda..."
+msgstr "Ugrás..."
 
 #: openbox/client_list_combined_menu.c:94
 msgid "Manage desktops"
@@ -118,7 +108,7 @@ msgstr "Munkaasztal-kezelés"
 
 #: openbox/client_list_combined_menu.c:95 openbox/client_list_menu.c:155
 msgid "_Add new desktop"
-msgstr "Új _munkaasztal"
+msgstr "Új munk_aasztal"
 
 #: openbox/client_list_combined_menu.c:96 openbox/client_list_menu.c:156
 msgid "_Remove last desktop"
@@ -154,7 +144,7 @@ msgstr "Mindig _alul"
 
 #: openbox/client_menu.c:379
 msgid "_Send to desktop"
-msgstr "Munkaasztalra _küldeni"
+msgstr "Munkaasztalra _küldés"
 
 #: openbox/client_menu.c:383
 msgid "Client menu"
@@ -166,15 +156,15 @@ msgstr "_Visszaállítás"
 
 #: openbox/client_menu.c:397
 msgid "_Move"
-msgstr "_Mozgatás"
+msgstr "Á_thelyezés"
 
 #: openbox/client_menu.c:399
 msgid "Resi_ze"
-msgstr "_Átméretezés"
+msgstr "Átmérete_zés"
 
 #: openbox/client_menu.c:401
 msgid "Ico_nify"
-msgstr "Iko_nná alakítás"
+msgstr "Iko_nizálás"
 
 #: openbox/client_menu.c:405
 msgid "Ma_ximize"
@@ -186,117 +176,121 @@ msgstr "_Görgetés fel/le"
 
 #: openbox/client_menu.c:411
 msgid "Un/_Decorate"
-msgstr "_Dekoráció eltávilítása"
+msgstr "_Dekoráció eltávolítása"
 
 #: openbox/client_menu.c:415
 msgid "_Close"
 msgstr "_Bezárás"
 
-#: openbox/config.c:781
+#: openbox/config.c:798
 #, c-format
 msgid "Invalid button \"%s\" specified in config file"
 msgstr "Érvénytelen gomb a konfigurációs fájlban \"%s\""
 
 #: openbox/keyboard.c:157
 msgid "Conflict with key binding in config file"
-msgstr "Ütköző billentyű-műveletek a konfigurációs fájlban"
+msgstr "Ütköző billentyű hozzárendelések a konfigurációs fájlban"
 
 #: openbox/menu.c:102 openbox/menu.c:110
 #, c-format
 msgid "Unable to find a valid menu file \"%s\""
-msgstr "Nem található ilyen érvényes menü fájl: \"%s\""
+msgstr "Nem található ilyen érvényes menüfájl: \"%s\""
 
 #: openbox/menu.c:170
 #, c-format
 msgid "Failed to execute command for pipe-menu \"%s\": %s"
-msgstr "Sikertelen parancsfuttatás a csővezeték-menüben \"%s\": %s"
+msgstr "Nem sikerült végrehajtani a parancsot a csővezeték-menüben \"%s\": %s"
 
 #: openbox/menu.c:184
 #, c-format
 msgid "Invalid output from pipe-menu \"%s\""
-msgstr "Érvnytelen válasz a csővezeték menüből \"%s\""
+msgstr "Érvnytelen kimenet a csővezeték-menüből \"%s\""
 
 #: openbox/menu.c:197
 #, c-format
 msgid "Attempted to access menu \"%s\" but it does not exist"
 msgstr "\"%s\" menü elérésére történt kísérlet, de az nem létezik"
 
-#: openbox/menu.c:367 openbox/menu.c:368
+#: openbox/menu.c:370 openbox/menu.c:371
 msgid "More..."
 msgstr "Tovább..."
 
 #: openbox/mouse.c:373
 #, c-format
 msgid "Invalid button \"%s\" in mouse binding"
-msgstr "Érvénytelen gomb \"%s\" az egér parancsoknál"
+msgstr "Érvénytelen gomb \"%s\" az egér hozzárendeléseknél"
 
 #: openbox/mouse.c:379
 #, c-format
 msgid "Invalid context \"%s\" in mouse binding"
-msgstr "Érvénytelen környezet az egér parancsoknál: \"%s\""
+msgstr "Érvénytelen környezet az egér hozzárendeléseknél: \"%s\""
 
 #: openbox/openbox.c:133
 #, c-format
 msgid "Unable to change to home directory \"%s\": %s"
-msgstr "Nem lehet a saját mappába váltani \"%s\": %s"
+msgstr "Nem lehet a saját könyvtárba váltani \"%s\": %s"
 
 #: openbox/openbox.c:152
 msgid "Failed to open the display from the DISPLAY environment variable."
-msgstr "Nem nyitható meg a DISPLAY változóban beállított képernyő"
+msgstr ""
+"Nem sikerült megnyitni a DISPLAY környezeti változóban beállított képernyőt."
 
 #: openbox/openbox.c:183
 msgid "Failed to initialize the obrender library."
-msgstr "Nem sikerült használatba venni az obernder függvénykönyvtárat"
+msgstr "Nem sikerült előkészíteni az obrender programkönyvtárat."
 
 #: openbox/openbox.c:194
 msgid "X server does not support locale."
-msgstr "Az X kiszolgáló nem támogatja ezt a nemzetközi beállítást."
+msgstr "Az X-kiszolgáló nem támogatja ezt a nemzetközi beállítást."
 
 #: openbox/openbox.c:196
 msgid "Cannot set locale modifiers for the X server."
-msgstr "A nemzetközi beálljtás módosítók nem állíthatók be az X szerveren."
+msgstr ""
+"Nem lehet beállítani a nemzetközi beállítás-módosítókat az X-kiszolgálón."
 
-#: openbox/openbox.c:263
+#: openbox/openbox.c:265
 msgid "Unable to find a valid config file, using some simple defaults"
-msgstr "Nincs konfigurációs fájl, ezért egyszerű alapértelmezéseket használunk"
+msgstr ""
+"Nem található érvényes konfigurációs fájl, ezért egyszerű alapértelmezés "
+"lesznek használva"
 
-#: openbox/openbox.c:297
+#: openbox/openbox.c:299
 msgid "Unable to load a theme."
-msgstr "Nem tölthető be a téma."
+msgstr "Nem lehet betölteni témát."
 
-#: openbox/openbox.c:377
+#: openbox/openbox.c:379
 #, c-format
 msgid ""
 "One or more XML syntax errors were found while parsing the Openbox "
 "configuration files.  See stdout for more information.  The last error seen "
 "was in file \"%s\" line %d, with message: %s"
 msgstr ""
-"Egy vagy több XML szintaktikai hibát találtam az Openbox konfigurációs fájl "
-"olvasásakor.  Nézd meg a standard kimenetet a részletekért.  Az utolsó hiba "
-"ebben a fájlban volt: \"%s\" a %d sorban. A hibaüzenet: %s"
+"Egy vagy több XML szintaktikai hiba található az Openbox konfigurációs fájl "
+"feldolgozásakor. További információkért tekintse meg a szabványos kimenetet. "
+"Az utolsó hiba ebben a fájlban volt: \"%s\" (%d sor). A hibaüzenet: %s"
 
-#: openbox/openbox.c:379
+#: openbox/openbox.c:381
 msgid "Openbox Syntax Error"
-msgstr "Openbox Szintaxis Hiba"
+msgstr "Openbox szintaktikai hiba"
 
-#: openbox/openbox.c:379
+#: openbox/openbox.c:381
 msgid "Close"
 msgstr "Bezárás"
 
-#: openbox/openbox.c:448
+#: openbox/openbox.c:463
 #, c-format
 msgid "Restart failed to execute new executable \"%s\": %s"
 msgstr "Az újraindítás során ez az új program nem volt indítható \"%s\": %s"
 
-#: openbox/openbox.c:518 openbox/openbox.c:520
+#: openbox/openbox.c:533 openbox/openbox.c:535
 msgid "Copyright (c)"
-msgstr "Szerzői jogok (c)"
+msgstr "Copyright (c)"
 
-#: openbox/openbox.c:529
+#: openbox/openbox.c:544
 msgid "Syntax: openbox [options]\n"
-msgstr "Használat: openbox [options]\n"
+msgstr "Használat: openbox [opciók]\n"
 
-#: openbox/openbox.c:530
+#: openbox/openbox.c:545
 msgid ""
 "\n"
 "Options:\n"
@@ -304,115 +298,115 @@ msgstr ""
 "\n"
 "Opciók:\n"
 
-#: openbox/openbox.c:531
+#: openbox/openbox.c:546
 msgid "  --help              Display this help and exit\n"
 msgstr "  --help              Súgó megjelenítése és kilépés\n"
 
-#: openbox/openbox.c:532
+#: openbox/openbox.c:547
 msgid "  --version           Display the version and exit\n"
-msgstr "  --version           Verzió kiírása majd kilépés\n"
+msgstr "  --version           Verzió kiírása és kilépés\n"
 
-#: openbox/openbox.c:533
+#: openbox/openbox.c:548
 msgid "  --replace           Replace the currently running window manager\n"
-msgstr "  --replace           Futó ablakkezelő cseréje\n"
+msgstr "  --replace           Jelenleg futó ablakkezelő cseréje\n"
 
 #. TRANSLATORS: if you translate "FILE" here, make sure to keep the "Specify..."
 #. aligned still, if you have to, make a new line with \n and 22 spaces. It's
 #. fine to leave it as FILE though.
-#: openbox/openbox.c:537
+#: openbox/openbox.c:552
 msgid "  --config-file FILE  Specify the path to the config file to use\n"
 msgstr ""
-"  --config-file FILE  Megadhatod az útvonalat a konfigurációs file-hoz\n"
+"  --config-file FÁJL  A használandó konfigurációs fájl útvonalának megadása\n"
 
-#: openbox/openbox.c:538
+#: openbox/openbox.c:553
 msgid "  --sm-disable        Disable connection to the session manager\n"
-msgstr "  --sm-disable        Ne csatlakozzon a szekció-kezelőhöz\n"
+msgstr "  --sm-disable        Ne csatlakozzon a munkamenet-kezelőhöz\n"
 
-#: openbox/openbox.c:539
+#: openbox/openbox.c:554
 msgid ""
 "\n"
 "Passing messages to a running Openbox instance:\n"
 msgstr ""
 "\n"
-"Üzenet küldése a futó Openbox példánynak\n"
+"Üzenet küldése a futó Openbox példánynak:\n"
 
-#: openbox/openbox.c:540
+#: openbox/openbox.c:555
 msgid "  --reconfigure       Reload Openbox's configuration\n"
-msgstr "  --reconfigure       Konfiguráció úrjatöltése\n"
+msgstr "  --reconfigure       Openbox beállításának újratöltése\n"
 
-#: openbox/openbox.c:541
+#: openbox/openbox.c:556
 msgid "  --restart           Restart Openbox\n"
 msgstr "  --restart           Openbox újraindítása\n"
 
-#: openbox/openbox.c:542
+#: openbox/openbox.c:557
 msgid "  --exit              Exit Openbox\n"
 msgstr "  --exit              Kilépés az Openboxból\n"
 
-#: openbox/openbox.c:543
+#: openbox/openbox.c:558
 msgid ""
 "\n"
 "Debugging options:\n"
 msgstr ""
 "\n"
-"Debug (hibakereső) lehetőségek:\n"
+"Hibakeresési opciók:\n"
 
-#: openbox/openbox.c:544
+#: openbox/openbox.c:559
 msgid "  --sync              Run in synchronous mode\n"
 msgstr "  --sync              Futtatás szinkron módban\n"
 
-#: openbox/openbox.c:545
+#: openbox/openbox.c:560
 msgid "  --debug             Display debugging output\n"
-msgstr "  --debug             Hibakeresési információk megjelenítése\n"
+msgstr "  --debug             Hibakeresési kimenet megjelenítése\n"
 
-#: openbox/openbox.c:546
+#: openbox/openbox.c:561
 msgid "  --debug-focus       Display debugging output for focus handling\n"
 msgstr ""
-"  --debug-focus       Fókuszkezelésre vonatkozó hibakeresési információk "
-"kiírása\n"
+"  --debug-focus       Fókuszkezelésre vonatkozó hibakeresési kimenetek "
+"megjelenítése\n"
 
-#: openbox/openbox.c:547
+#: openbox/openbox.c:562
 msgid "  --debug-xinerama    Split the display into fake xinerama screens\n"
 msgstr "  --debug-xinerama    Képernyő felosztása két ál-xinerama képernyőre\n"
 
-#: openbox/openbox.c:548
+#: openbox/openbox.c:563
 #, c-format
 msgid ""
 "\n"
 "Please report bugs at %s\n"
 msgstr ""
 "\n"
-"Légyszi jelentsd a hibát itt: %s\n"
+"Kérjük a hibákat itt jelentse:  %s\n"
 
-#: openbox/openbox.c:617
+#: openbox/openbox.c:645
 msgid "--config-file requires an argument\n"
-msgstr "--config-file használatakor paraméter megadása kötelező!\n"
+msgstr "--config-file használatakor paraméter megadása kötelező\n"
 
-#: openbox/openbox.c:660
+#: openbox/openbox.c:688
 #, c-format
 msgid "Invalid command line argument \"%s\"\n"
 msgstr "Érvénytelen parancssori opció: \"%s\"\n"
 
-#: openbox/screen.c:102 openbox/screen.c:190
+#: openbox/screen.c:103 openbox/screen.c:191
 #, c-format
 msgid "A window manager is already running on screen %d"
-msgstr "Már fut egy ablakkezelő ezen a képernyőn %d"
+msgstr "Már fut egy ablakkezelő ezen a képernyőn: %d"
 
-#: openbox/screen.c:124
+#: openbox/screen.c:125
 #, c-format
 msgid "Could not acquire window manager selection on screen %d"
-msgstr "Nem tudok ablakkezelőt váltani ezen a képernyőn %d"
+msgstr "Nem lehet ablakkezelőt váltani ezen a képernyőn: %d"
 
-#: openbox/screen.c:145
+#: openbox/screen.c:146
 #, c-format
 msgid "The WM on screen %d is not exiting"
-msgstr "Ezen a képernyőn: %d az ablakkezelő nem lép ki"
+msgstr "Nem lép ki az ablakkezelő ezen a képernyőn: %d"
 
 #. TRANSLATORS: If you need to specify a different order of the
 #. arguments, you can use %1$d for the first one and %2$d for the
 #. second one. For example,
 #. "The current session has %2$d desktops, but Openbox is configured for %1$d ..."
-#: openbox/screen.c:412
-#, fuzzy, c-format
+#: openbox/screen.c:416
+#, c-format
 msgid ""
 "Openbox is configured for %d desktop, but the current session has %d.  "
 "Overriding the Openbox configuration."
@@ -421,68 +415,66 @@ msgid_plural ""
 "Overriding the Openbox configuration."
 msgstr[0] ""
 "Az Openbox %d munkaasztal használatára lett beállítva, de a jelenlegi "
-"munkamenetnek %d van.  Felülbíráljuk az Openbox beállítását."
+"munkamenetnek %d van. Felülbíráljuk az Openbox beállítását."
 msgstr[1] ""
 "Az Openbox %d munkaasztal használatára lett beállítva, de a jelenlegi "
-"munkamenetnek %d van.  Felülbíráljuk az Openbox beállítását."
+"munkamenetnek %d van. Felülbíráljuk az Openbox beállítását."
 
-#: openbox/screen.c:1180
+#: openbox/screen.c:1199
 #, c-format
 msgid "desktop %i"
 msgstr "%i. munkaasztal"
 
-#: openbox/session.c:104
+#: openbox/session.c:105
 #, c-format
 msgid "Unable to make directory \"%s\": %s"
-msgstr "Nem hozható létre a könyvtár \"%s\": %s"
+msgstr "Nem lehet létrehozni a könyvtárat \"%s\": %s"
 
-#: openbox/session.c:466
+#: openbox/session.c:472
 #, c-format
 msgid "Unable to save the session to \"%s\": %s"
-msgstr "Nem tudom elmenti ide a futó környezetet \"%s\": %s"
+msgstr "Nem lehet menteni ide a futó munkamenetet \"%s\": %s"
 
-#: openbox/session.c:605
+#: openbox/session.c:611
 #, c-format
 msgid "Error while saving the session to \"%s\": %s"
-msgstr "Hiba a futási környezet mentése közben \"%s\": %s"
+msgstr "Hiba a munkamenet mentése közben \"%s\": %s"
 
-#: openbox/session.c:842
+#: openbox/session.c:848
 msgid "Not connected to a session manager"
-msgstr "Nem kapcsolódunk a szekciókezelőhöz"
+msgstr "Nincs kapcsolódva a munkamenet-kezelőhöz"
 
 #: openbox/startupnotify.c:243
 #, c-format
 msgid "Running %s"
-msgstr "Futtatás %s"
+msgstr "%s futtatása"
 
 #: openbox/translate.c:59
 #, c-format
 msgid "Invalid modifier key \"%s\" in key/mouse binding"
-msgstr "Érvénytelen módosító gomb \"%s\" egér vagy billentyűparancsnál"
+msgstr ""
+"Érvénytelen módosító billentyű \"%s\" billentyű vagy egér hozzárendelésnél"
 
 #: openbox/translate.c:138
 #, c-format
 msgid "Invalid key code \"%s\" in key binding"
-msgstr "Érvénytelen billentyűkód \"%s\" billentyűparancsnál"
+msgstr "Érvénytelen billentyűkód \"%s\" billentyű hozzárendelésnél"
 
 #: openbox/translate.c:145
 #, c-format
 msgid "Invalid key name \"%s\" in key binding"
-msgstr "Érvénytelen billentyűnév \"%s\" billentyűparancsnál"
+msgstr "Érvénytelen billentyűnév \"%s\" billentyű hozzárendelésnél"
 
 #: openbox/translate.c:151
 #, c-format
 msgid "Requested key \"%s\" does not exist on the display"
-msgstr "A kért gomb \"%s\" nem létezik a képernyőn"
+msgstr "A kért billentyű \"%s\" nem létezik a képernyőn"
 
 #: openbox/xerror.c:40
 #, c-format
 msgid "X Error: %s"
-msgstr "X rendszer hiba: %s"
+msgstr "X-hiba: %s"
 
 #: openbox/prompt.c:200
 msgid "OK"
 msgstr "OK"
-
-#~ msgid "Failed to execute \"%s\": %s"
-#~ msgstr "Nem sikerült futtatni ezt a programot \"%s\": %s"
index 4af2e9b..31a070f 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -296,7 +296,7 @@ msgstr "著作権 (c)"
 
 #: openbox/openbox.c:529
 msgid "Syntax: openbox [options]\n"
-msgstr "使い方: openbox [オプション]\n"
+msgstr "用法: openbox [オプション]\n"
 
 #: openbox/openbox.c:530
 msgid ""
index f1a3ae1..1642afe 100644 (file)
--- a/po/lv.po
+++ b/po/lv.po
@@ -1,26 +1,27 @@
 # Latvian translations for openbox.
-# Copyright (C) 2009 Dana Jansens
+# Copyright (C) 2010 Dana Jansens
 # This file is distributed under the same license as the openbox package.
-# Einars Sprugis  <einars8@gmail.com>, 2009.
 #
+# Einars Sprugis <einars8@gmail.com>, 2010.
 msgid ""
 msgstr ""
-"Project-Id-Version: Openbox 3.4.7\n"
+"Project-Id-Version: 3.4.10\n"
 "Report-Msgid-Bugs-To: http://bugzilla.icculus.org\n"
-"POT-Creation-Date: 2009-03-31 19:16+0200\n"
-"PO-Revision-Date: 2009-03-30 19:14+0300\n"
+"POT-Creation-Date: 2010-01-10 22:21+0100\n"
+"PO-Revision-Date: 2010-01-08 21:11+0200\n"
 "Last-Translator: Einars Sprugis <einars8@gmail.com>\n"
-"Language-Team: Latvian <lv@li.org>\n"
+"Language-Team: Latvian <locale@laka.lv>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : "
 "2);\n"
+"X-Generator: Lokalize 1.0\n"
 
 #: openbox/actions.c:149
 #, c-format
 msgid "Invalid action \"%s\" requested. No such action exists."
-msgstr "Neatļauta darbība \"%s\". Šāda darbība neeksistē."
+msgstr "Prasīta neatļauta darbība \"%s\". Šāda darbība neeksistē."
 
 #: openbox/actions/execute.c:128
 msgid "No"
@@ -39,72 +40,63 @@ msgstr "Izpildīt"
 msgid "Failed to convert the path \"%s\" from utf8"
 msgstr "Neizdevās pārveidot ceļu \"%s\" no utf8"
 
-#: openbox/actions/exit.c:52 openbox/actions/session.c:64
-#: openbox/client.c:3465
+#: openbox/actions/exit.c:62 openbox/client.c:3474
 msgid "Cancel"
 msgstr "Atcelt"
 
-#: openbox/actions/exit.c:53
+#: openbox/actions/exit.c:63
 msgid "Exit"
 msgstr "Iziet"
 
-#: openbox/actions/exit.c:56
+#: openbox/actions/exit.c:67
+msgid "Are you sure you want to log out?"
+msgstr "Vai tiešām vēlaties atteikties?"
+
+#: openbox/actions/exit.c:68
+msgid "Log Out"
+msgstr "Atteikties"
+
+#: openbox/actions/exit.c:71
 msgid "Are you sure you want to exit Openbox?"
 msgstr "Vai tiešām vēlaties iziet no Openbox?"
 
-#: openbox/actions/exit.c:57
+#: openbox/actions/exit.c:72
 msgid "Exit Openbox"
 msgstr "Iziet no Openbox"
 
-#. TRANSLATORS: Don't translate the word "SessionLogout" as it's the
-#. name of the action you write in rc.xml
-#: openbox/actions/session.c:43
-msgid ""
-"The SessionLogout action is not available since Openbox was built without "
-"session management support"
-msgstr ""
-"SessionLogout darbība nav pieejama, jo Openbox tika kompilēts bez sesijas "
-"pārvaldes atbalsta"
-
-#: openbox/actions/session.c:65 openbox/actions/session.c:70
-msgid "Log Out"
-msgstr "Atteikties"
-
-#: openbox/actions/session.c:69
-msgid "Are you sure you want to log out?"
-msgstr "Vai tiešām vēlaties atteikties?"
-
-#: openbox/client.c:2012
+#: openbox/client.c:2016
 msgid "Unnamed Window"
 msgstr "Logs bez nosaukuma"
 
-#: openbox/client.c:2026 openbox/client.c:2058
+#: openbox/client.c:2030 openbox/client.c:2062
 msgid "Killing..."
 msgstr "Nogalina..."
 
-#: openbox/client.c:2028 openbox/client.c:2060
+#: openbox/client.c:2032 openbox/client.c:2064
 msgid "Not Responding"
 msgstr "Neatbild"
 
-#: openbox/client.c:3454
+#: openbox/client.c:3463
 #, c-format
 msgid ""
 "The window \"%s\" does not seem to be responding.  Do you want to force it "
 "to exit by sending the %s signal?"
-msgstr "Logs \"%s\" neatbild. Vai vēlieties to piespiest, nosūtot signālu %s?"
+msgstr ""
+"Logs \"%s\" neatbild. Vai vēlieties to aizvērt piespiedu kārtā, nosūtot "
+"signālu %s?"
 
-#: openbox/client.c:3456
+#: openbox/client.c:3465
 msgid "End Process"
 msgstr "Nobeigt procesu"
 
-#: openbox/client.c:3460
+#: openbox/client.c:3469
 #, c-format
 msgid ""
 "The window \"%s\" does not seem to be responding.  Do you want to disconnect "
 "it from the X server?"
 msgstr "Logs \"%s\" neatbild. Vai vēlaties to atvienot no X servera?"
 
-#: openbox/client.c:3462
+#: openbox/client.c:3471
 msgid "Disconnect"
 msgstr "Atvienot"
 
@@ -122,7 +114,7 @@ msgstr "Pievienot j_aunu darbvirsmu"
 
 #: openbox/client_list_combined_menu.c:96 openbox/client_list_menu.c:156
 msgid "_Remove last desktop"
-msgstr "Aizvākt pēdējo da_rbvirsmu"
+msgstr "Noņemt pēdējo da_rbvirsmu"
 
 #: openbox/client_list_combined_menu.c:149
 msgid "Windows"
@@ -146,7 +138,7 @@ msgstr "Vienmēr augšā"
 
 #: openbox/client_menu.c:376
 msgid "_Normal"
-msgstr "_Normāli"
+msgstr "_Normāls"
 
 #: openbox/client_menu.c:377
 msgid "Always on _bottom"
@@ -158,7 +150,7 @@ msgstr "No_sūtīt uz darbvirsmu"
 
 #: openbox/client_menu.c:383
 msgid "Client menu"
-msgstr "Klientizvēlne"
+msgstr "Klientizvēlne"
 
 #: openbox/client_menu.c:393
 msgid "R_estore"
@@ -192,7 +184,7 @@ msgstr "Bez/Ar _dekorācijām"
 msgid "_Close"
 msgstr "Ai_zvērt"
 
-#: openbox/config.c:782
+#: openbox/config.c:798
 #, c-format
 msgid "Invalid button \"%s\" specified in config file"
 msgstr "Konfigurācijas failā \"%s\" norādīts neatļauts taustiņš"
@@ -221,7 +213,7 @@ msgstr "Neatļauta izvade no skriptētās izvēlnes \"%s\""
 msgid "Attempted to access menu \"%s\" but it does not exist"
 msgstr "Mēģināja piekļūt izvēlnei \"%s\", bet tā neeksistē"
 
-#: openbox/menu.c:367 openbox/menu.c:368
+#: openbox/menu.c:370 openbox/menu.c:371
 msgid "More..."
 msgstr "Vairāk..."
 
@@ -242,7 +234,7 @@ msgstr "Nevarēja pāriet uz mājas mapi \"%s\": %s"
 
 #: openbox/openbox.c:152
 msgid "Failed to open the display from the DISPLAY environment variable."
-msgstr "Neizdevās atvēŗt displeju no DISPLAY vides mainīgā."
+msgstr "Neizdevās atvērt displeju no DISPLAY vides mainīgā."
 
 #: openbox/openbox.c:183
 msgid "Failed to initialize the obrender library."
@@ -256,80 +248,80 @@ msgstr "X serveris neatbalsta lokāli."
 msgid "Cannot set locale modifiers for the X server."
 msgstr "Nevar uzstādīt lokāles modificētājus X serverim."
 
-#: openbox/openbox.c:263
+#: openbox/openbox.c:265
 msgid "Unable to find a valid config file, using some simple defaults"
 msgstr ""
 "Nevarēja atrast atļautu konfigurācijas failu, tiek izmantoti noklusējumi"
 
-#: openbox/openbox.c:297
+#: openbox/openbox.c:299
 msgid "Unable to load a theme."
 msgstr "Nebija iespējams ielādēt tēmu."
 
-#: openbox/openbox.c:377
+#: openbox/openbox.c:379
 #, c-format
 msgid ""
 "One or more XML syntax errors were found while parsing the Openbox "
 "configuration files.  See stdout for more information.  The last error seen "
 "was in file \"%s\" line %d, with message: %s"
 msgstr ""
-"Analizējot Openbox konfigurācijas datnes, tika atrastas viena vai vairākas "
+"Analizējot Openbox konfigurācijas failus, tika atrastas viena vai vairākas "
 "XML sintakses kļūdas. Aplūkojiet standarta izvadi, lai noskaidrotu vairāk. "
 "Pēdējā kļūda bija failā \"%s\" - %d rinda, kļūdas ziņojums: %s"
 
-#: openbox/openbox.c:379
+#: openbox/openbox.c:381
 msgid "Openbox Syntax Error"
 msgstr "Openbox sintakses kļūda"
 
-#: openbox/openbox.c:379
+#: openbox/openbox.c:381
 msgid "Close"
 msgstr "Aizvērt"
 
-#: openbox/openbox.c:448
+#: openbox/openbox.c:463
 #, c-format
 msgid "Restart failed to execute new executable \"%s\": %s"
-msgstr ""
+msgstr "Pārstartētājam neizdevās palaist jauno izpildāmo \"%s\": %s"
 
-#: openbox/openbox.c:518 openbox/openbox.c:520
+#: openbox/openbox.c:533 openbox/openbox.c:535
 msgid "Copyright (c)"
-msgstr "Copyright (c)"
+msgstr "Autortiesības (c)"
 
-#: openbox/openbox.c:529
+#: openbox/openbox.c:544
 msgid "Syntax: openbox [options]\n"
-msgstr "Sintakse: openbox [iespējas]\n"
+msgstr "Sintakse: openbox [opcijas]\n"
 
-#: openbox/openbox.c:530
+#: openbox/openbox.c:545
 msgid ""
 "\n"
 "Options:\n"
 msgstr ""
 "\n"
-"Iespējas:\n"
+"Opcijas:\n"
 
-#: openbox/openbox.c:531
+#: openbox/openbox.c:546
 msgid "  --help              Display this help and exit\n"
 msgstr "  --help              Parāda šo palīdzības tekstu un iziet\n"
 
-#: openbox/openbox.c:532
+#: openbox/openbox.c:547
 msgid "  --version           Display the version and exit\n"
 msgstr "  --version           Parāda versiju un iziet\n"
 
-#: openbox/openbox.c:533
+#: openbox/openbox.c:548
 msgid "  --replace           Replace the currently running window manager\n"
 msgstr "  --replace           Aizvieto pašreiz palaisto logu pārvaldnieku\n"
 
 #. TRANSLATORS: if you translate "FILE" here, make sure to keep the "Specify..."
 #. aligned still, if you have to, make a new line with \n and 22 spaces. It's
 #. fine to leave it as FILE though.
-#: openbox/openbox.c:537
+#: openbox/openbox.c:552
 msgid "  --config-file FILE  Specify the path to the config file to use\n"
 msgstr ""
 "  --config-file FAILS Norāda ceļu uz izmantojamo konfigurācijas failu\n"
 
-#: openbox/openbox.c:538
+#: openbox/openbox.c:553
 msgid "  --sm-disable        Disable connection to the session manager\n"
-msgstr "  --sm-disable        Atspējo savienojumu ar sesiju pārvaldnieku\n"
+msgstr "  --sm-disable        Pārtrauc savienojumu ar sesiju pārvaldnieku\n"
 
-#: openbox/openbox.c:539
+#: openbox/openbox.c:554
 msgid ""
 "\n"
 "Passing messages to a running Openbox instance:\n"
@@ -337,19 +329,19 @@ msgstr ""
 "\n"
 "Nodod ziņojumus esošai Openbox instancei:\n"
 
-#: openbox/openbox.c:540
+#: openbox/openbox.c:555
 msgid "  --reconfigure       Reload Openbox's configuration\n"
 msgstr "  --reconfigure       Pārlādē Openbox konfigurācijas failus\n"
 
-#: openbox/openbox.c:541
+#: openbox/openbox.c:556
 msgid "  --restart           Restart Openbox\n"
 msgstr "  --restart           Pārstartē Openbox\n"
 
-#: openbox/openbox.c:542
+#: openbox/openbox.c:557
 msgid "  --exit              Exit Openbox\n"
 msgstr "  --exit              Iziet no Openbox\n"
 
-#: openbox/openbox.c:543
+#: openbox/openbox.c:558
 msgid ""
 "\n"
 "Debugging options:\n"
@@ -357,24 +349,24 @@ msgstr ""
 "\n"
 "Atkļūdošanas iespējas:\n"
 
-#: openbox/openbox.c:544
+#: openbox/openbox.c:559
 msgid "  --sync              Run in synchronous mode\n"
 msgstr "  --sync              Palaist sinhronajā režīmā\n"
 
-#: openbox/openbox.c:545
+#: openbox/openbox.c:560
 msgid "  --debug             Display debugging output\n"
 msgstr "  --debug             Rādīt atkļūdošanas izvadi\n"
 
-#: openbox/openbox.c:546
+#: openbox/openbox.c:561
 msgid "  --debug-focus       Display debugging output for focus handling\n"
 msgstr "  --debug-focus       Rādīt atkļūdošanas izvadi fokusēšanas darbībām\n"
 
-#: openbox/openbox.c:547
+#: openbox/openbox.c:562
 msgid "  --debug-xinerama    Split the display into fake xinerama screens\n"
 msgstr ""
 "  --debug-xinerama    Sadalīt displeju vairākos viltus xinerama ekrānos\n"
 
-#: openbox/openbox.c:548
+#: openbox/openbox.c:563
 #, c-format
 msgid ""
 "\n"
@@ -383,26 +375,26 @@ msgstr ""
 "\n"
 "Lūdzu, ziņojiet kļūdas %s\n"
 
-#: openbox/openbox.c:617
+#: openbox/openbox.c:645
 msgid "--config-file requires an argument\n"
 msgstr "--config-file vajadzīgs arguments\n"
 
-#: openbox/openbox.c:660
+#: openbox/openbox.c:688
 #, c-format
 msgid "Invalid command line argument \"%s\"\n"
 msgstr "Neatļauts komandrindas arguments \"%s\"\n"
 
-#: openbox/screen.c:102 openbox/screen.c:190
+#: openbox/screen.c:103 openbox/screen.c:191
 #, c-format
 msgid "A window manager is already running on screen %d"
-msgstr "Logu pārvaldnieks jau eksistē uz %d. ekrāna"
+msgstr "Logu pārvaldnieks jau palaists uz %d. ekrāna"
 
-#: openbox/screen.c:124
+#: openbox/screen.c:125
 #, c-format
 msgid "Could not acquire window manager selection on screen %d"
 msgstr "Nevarēja iegūt logu pārvaldnieka izvēli uz %d. ekrāna"
 
-#: openbox/screen.c:145
+#: openbox/screen.c:146
 #, c-format
 msgid "The WM on screen %d is not exiting"
 msgstr "Logu pārvaldnieks uz %d. ekrāna nebeidz darbību"
@@ -411,7 +403,7 @@ msgstr "Logu pārvaldnieks uz %d. ekrāna nebeidz darbību"
 #. arguments, you can use %1$d for the first one and %2$d for the
 #. second one. For example,
 #. "The current session has %2$d desktops, but Openbox is configured for %1$d ..."
-#: openbox/screen.c:412
+#: openbox/screen.c:416
 #, c-format
 msgid ""
 "Openbox is configured for %d desktop, but the current session has %d.  "
@@ -429,27 +421,27 @@ msgstr[2] ""
 "Openbox ir konfigurēts %d darbvirsmām, bet pašreizējai sesijai tādu ir %d.  "
 "Šī Openbox konfigurācijas opcija tiks ignorēta."
 
-#: openbox/screen.c:1180
+#: openbox/screen.c:1199
 #, c-format
 msgid "desktop %i"
 msgstr "darbvirsma %i"
 
-#: openbox/session.c:104
+#: openbox/session.c:105
 #, c-format
 msgid "Unable to make directory \"%s\": %s"
-msgstr "Nav iespējams izveidot mapi \"%s\": %s"
+msgstr "Nevarēja izveidot mapi \"%s\": %s"
 
-#: openbox/session.c:466
+#: openbox/session.c:472
 #, c-format
 msgid "Unable to save the session to \"%s\": %s"
-msgstr "Nav iespējams saglabāt sesiju \"%s\": %s"
+msgstr "Neizdevās saglabāt sesiju \"%s\": %s"
 
-#: openbox/session.c:605
+#: openbox/session.c:611
 #, c-format
 msgid "Error while saving the session to \"%s\": %s"
 msgstr "Kļūda saglabājot sesiju \"%s\": %s"
 
-#: openbox/session.c:842
+#: openbox/session.c:848
 msgid "Not connected to a session manager"
 msgstr "Nav savienots ar sesiju pārvaldnieku"
 
@@ -486,3 +478,10 @@ msgstr "X kļūda: %s"
 #: openbox/prompt.c:200
 msgid "OK"
 msgstr "Labi"
+
+#~ msgid ""
+#~ "The SessionLogout action is not available since Openbox was built without "
+#~ "session management support"
+#~ msgstr ""
+#~ "Darbība 'SessionLogout' nav pieejama, jo Openbox ir kompilēts bez sesiju "
+#~ "pārvaldības atbalsta"
index 6ea8a4d..44b3304 100644 (file)
@@ -12,7 +12,7 @@ gint fail(const gchar *s) {
     else
         fprintf
             (stderr,
-             "Usage: obxprop [OPTIONS]\n\n"
+             "Usage: obxprop [OPTIONS] [--] [PROPERTIES ...]\n\n"
              "Options:\n"
              "    --help              Display this help and exit\n"
              "    --display DISPLAY   Connect to this X display\n"
@@ -227,7 +227,7 @@ gboolean read_prop(Display *d, Window w, Atom prop, const gchar **type, gchar **
     return FALSE;
 }
 
-void show_properties(Display *d, Window w)
+void show_properties(Display *d, Window w, int argc, char **argv)
 {
     Atom* props;
     int i, n;
@@ -241,7 +241,19 @@ void show_properties(Display *d, Window w)
         name = XGetAtomName(d, props[i]);
 
         if (read_prop(d, w, props[i], &type, &val)) {
-            g_print("%s(%s) = %s\n", name, type, val);
+            int found = 1;
+            if (argc) {
+                int i;
+
+                found = 0;
+                for (i = 0; i < argc; i++)
+                    if (!strcmp(name, argv[i])) {
+                        found = 1;
+                        break;
+                    }
+            }
+            if (found)
+                g_print("%s(%s) = %s\n", name, type, val);
             g_free(val);
         }
 
@@ -261,13 +273,13 @@ int main(int argc, char **argv)
 
     for (i = 1; i < argc; ++i) {
         if (!strcmp(argv[i], "--help")) {
-            return fail(0);
+            return fail(NULL);
         }
         else if (!strcmp(argv[i], "--root"))
             root = TRUE;
         else if (!strcmp(argv[i], "--id")) {
             if (++i == argc)
-                return fail(0);
+                return fail(NULL);
             if (argv[i][0] == '0' && argv[i][1] == 'x') {
                 /* hex */
                 userid = parse_hex(argv[i]+2);
@@ -276,13 +288,22 @@ int main(int argc, char **argv)
                 /* decimal */
                 userid = atoi(argv[i]);
             }
-            break;
+            if (!userid)
+                return fail("Unable to parse argument to --id.");
         }
         else if (!strcmp(argv[i], "--display")) {
             if (++i == argc)
-                return fail(0);
+                return fail(NULL);
             dname = argv[i];
         }
+        else if (*argv[i] != '-')
+            break;
+        else if (!strcmp(argv[i], "--")) {
+            i++;
+            break;
+        }
+        else
+            return fail(NULL);
     }
 
     d = XOpenDisplay(dname);
@@ -295,12 +316,13 @@ int main(int argc, char **argv)
         userid = RootWindow(d, DefaultScreen(d));
 
     if (userid == None) {
-        i = XGrabPointer(d, RootWindow(d, DefaultScreen(d)),
+        int j;
+        j = XGrabPointer(d, RootWindow(d, DefaultScreen(d)),
                          False, ButtonPressMask,
                          GrabModeAsync, GrabModeAsync,
                          None, XCreateFontCursor(d, XC_crosshair),
                          CurrentTime);
-        if (i != GrabSuccess)
+        if (j != GrabSuccess)
             return fail("Unable to grab the pointer device");
         while (1) {
             XEvent ev;
@@ -312,14 +334,15 @@ int main(int argc, char **argv)
                 break;
             }
         }
+        id = find_client(d, userid);
     }
-
-    id = find_client(d, userid);
+    else
+        id = userid; /* they picked this one */
 
     if (id == None)
         return fail("Unable to find window with the requested ID");
 
-    show_properties(d, id);
+    show_properties(d, id, argc - i, &argv[i]);
     
     XCloseDisplay(d);
 
diff --git a/version.h.in b/version.h.in
new file mode 100644 (file)
index 0000000..1cfeb5c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef ob__version_h
+#define ob__version_h
+
+#define OPENBOX_VERSION "@OPENBOX_VERSION@"
+
+#endif