diff options
author | Alexey Korop | 2015-07-07 19:27:00 +0300 |
---|---|---|
committer | Alexey Korop | 2015-07-07 19:27:00 +0300 |
commit | 77c4006495da9dd9dd9a4f561c4775b11a2a8fe0 (patch) | |
tree | a57d259a892753460ab1a4ebef38765ee3009cbd | |
download | aur-77c4006495da9dd9dd9a4f561c4775b11a2a8fe0.tar.gz |
Initial import
-rw-r--r-- | .SRCINFO | 74 | ||||
-rw-r--r-- | PKGBUILD | 119 | ||||
-rw-r--r-- | clearclick.patch | 68 | ||||
-rw-r--r-- | clm_w_sub6.patch | 994 | ||||
-rw-r--r-- | compact_menu.patch | 12 | ||||
-rw-r--r-- | disable_edges_by_default.patch | 55 | ||||
-rw-r--r-- | edge_mikabox.patch | 396 | ||||
-rw-r--r-- | import-bind.patch | 107 | ||||
-rwxr-xr-x | install | 14 | ||||
-rw-r--r-- | keybind_item.patch | 44 | ||||
-rw-r--r-- | keybind_menu2.patch | 161 | ||||
-rw-r--r-- | menu.xml | 37 | ||||
-rw-r--r-- | menu_w_def9.patch | 754 | ||||
-rw-r--r-- | rc.xml | 76 | ||||
-rw-r--r-- | strict_skip_taskbar.patch | 53 | ||||
-rw-r--r-- | topmenu_kbd_group.patch | 59 | ||||
-rw-r--r-- | topmenu_kbd_group_local.patch | 63 | ||||
-rw-r--r-- | utf8-menu-accelerators.diff | 166 |
18 files changed, 3252 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..a7652535e1bb --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,74 @@ +pkgbase = openbox_eui + pkgdesc = Highly configurable and lightweight X11 window manager + pkgver = 2015.03.31 + pkgrel = 2 + url = http://openbox.org + install = install + arch = i686 + arch = x86_64 + groups = lxde + license = GPL + makedepends = binutils + makedepends = git + makedepends = patch + makedepends = libtool + makedepends = automake + makedepends = autoconf + makedepends = m4 + makedepends = make + makedepends = pkg-config + makedepends = gcc + makedepends = fakeroot + makedepends = docbook-to-man + depends = startup-notification + depends = libxml2 + depends = libxinerama + depends = libxrandr + depends = libxcursor + depends = pango + depends = imlib2 + depends = librsvg + depends = libsm + optdepends = kdebase-workspace: for the KDE/Openbox xsession + optdepends = python2-xdg: for the openbox-xdg-autostart script + provides = openbox + conflicts = openbox + backup = etc/xdg/openbox/menu.xml + backup = etc/xdg/openbox/rc.xml + backup = etc/xdg/openbox/autostart + backup = etc/xdg/openbox/environment + source = menu_w_def9.patch + source = clm_w_sub6.patch + source = keybind_item.patch + source = keybind_menu2.patch + source = clearclick.patch + source = topmenu_kbd_group.patch + source = import-bind.patch + source = edge_mikabox.patch + source = disable_edges_by_default.patch + source = compact_menu.patch + source = utf8-menu-accelerators.diff + source = topmenu_kbd_group_local.patch + source = strict_skip_taskbar.patch + source = menu.xml + source = rc.xml + source = install + md5sums = 90d3238b062f0631988ef788b8bb3dd6 + md5sums = 36545d5c124f0eb648a46fc2779e3dfe + md5sums = 816d283ba870b1c8494691fc3cd41ba2 + md5sums = 599e87ae3ce608d5f710075b8e59459a + md5sums = f42dda01e070fe1f270942c185adefe4 + md5sums = 68bf6c7ad5a04ac74b9b5744a2197b17 + md5sums = f10d80373150df6cb08501e6fa6e9c39 + md5sums = 1b9192e741ac98a1a541c93e137c0a70 + md5sums = 4d5fbf07973c13aaf86db31dacdbc0ae + md5sums = 3718f41d8573d5d2a4cf04536562b93a + md5sums = 6579e6898e3195fb6877e356b2092bba + md5sums = fabc9f22ebdda17649b7c98fd8fc4d81 + md5sums = e6a16b0be7eac066976fc56ed0bd1b27 + md5sums = 1ea5cf52cc72fd7b18f50798d1458baf + md5sums = e2e2480a2dfe13e93de5fa88c17eaa77 + md5sums = da62476c79a186e0313578963b2ee637 + +pkgname = openbox_eui + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..1f6b59d4e94a --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,119 @@ +# Maintainer: Alexey Korop <akorop@ukr.net> + +pkgname=openbox_eui +pkgver=2015.03.31 +pkgrel=2 +pkgdesc='Highly configurable and lightweight X11 window manager' +arch=('i686' 'x86_64') +url='http://openbox.org' +conflicts=('openbox') +provides=('openbox') +license=('GPL') +makedepends=(binutils git patch libtool automake autoconf m4 make pkg-config gcc fakeroot docbook-to-man) +depends=('startup-notification' 'libxml2' 'libxinerama' 'libxrandr' + 'libxcursor' 'pango' 'imlib2' 'librsvg' 'libsm') +optdepends=('kdebase-workspace: for the KDE/Openbox xsession' + 'python2-xdg: for the openbox-xdg-autostart script') +groups=('lxde') +backup=('etc/xdg/openbox/menu.xml' 'etc/xdg/openbox/rc.xml' + 'etc/xdg/openbox/autostart' 'etc/xdg/openbox/environment') +source=( +'menu_w_def9.patch' +'clm_w_sub6.patch' +'keybind_item.patch' +'keybind_menu2.patch' +'clearclick.patch' +'topmenu_kbd_group.patch' +'import-bind.patch' +'edge_mikabox.patch' +'disable_edges_by_default.patch' +'compact_menu.patch' +'utf8-menu-accelerators.diff' +'topmenu_kbd_group_local.patch' +'strict_skip_taskbar.patch' +'menu.xml' +'rc.xml' +'install' +) +md5sums=( + '90d3238b062f0631988ef788b8bb3dd6' + '36545d5c124f0eb648a46fc2779e3dfe' + '816d283ba870b1c8494691fc3cd41ba2' + '599e87ae3ce608d5f710075b8e59459a' + 'f42dda01e070fe1f270942c185adefe4' + '68bf6c7ad5a04ac74b9b5744a2197b17' + 'f10d80373150df6cb08501e6fa6e9c39' + '1b9192e741ac98a1a541c93e137c0a70' + '4d5fbf07973c13aaf86db31dacdbc0ae' + '3718f41d8573d5d2a4cf04536562b93a' + '6579e6898e3195fb6877e356b2092bba' + 'fabc9f22ebdda17649b7c98fd8fc4d81' + 'e6a16b0be7eac066976fc56ed0bd1b27' + '1ea5cf52cc72fd7b18f50798d1458baf' + 'e2e2480a2dfe13e93de5fa88c17eaa77' + 'da62476c79a186e0313578963b2ee637' +) + +prepare() { + git clone https://github.com/danakj/openbox.git + cd openbox + git reset --hard 9e8813e111cbe6c1088f6abbc771a29470f05fc2 + sed -i 's|/usr/bin/env python|/usr/bin/env python2|' \ + data/autostart/openbox-xdg-autostart +} + +build() { + cd openbox + echo menu_w_def9.patch + patch -p1 < ../menu_w_def9.patch + echo clm_w_sub6.patch + patch -p1 < ../clm_w_sub6.patch + echo keybind_item.patch + patch -p1 < ../keybind_item.patch + echo keybind_menu2.patch + patch -p1 < ../keybind_menu2.patch + echo clearclick.patch + patch -p1 < ../clearclick.patch + echo topmenu_kbd_group.patch + patch -p1 < ../topmenu_kbd_group.patch + echo import-bind.patch + patch -p1 < ../import-bind.patch + echo edge_mikabox.patch + patch -p1 < ../edge_mikabox.patch + echo disable_edges_by_default.patch + patch -p1 < ../disable_edges_by_default.patch + echo compact_menu.patch + patch -p1 < ../compact_menu.patch + echo utf8-menu-accelerators.diff + patch -p1 < ../utf8-menu-accelerators.diff + echo topmenu_kbd_group.patch_local + patch -p1 < ../topmenu_kbd_group_local.patch + echo strict_skip_taskbar + patch -p1 < ../strict_skip_taskbar.patch + ./bootstrap + ./configure --prefix=/usr \ + --with-x \ + --enable-startup-notification \ + --sysconfdir=/etc \ + --libexecdir=/usr/lib/openbox + make +} + +package() { + cd openbox + make DESTDIR="$pkgdir" install + + # GNOME Panel is no longer available in the official repositories + rm -r "$pkgdir"/usr/bin/{gdm-control,gnome-panel-control,openbox-gnome-session} \ + "$pkgdir"/usr/share/gnome{,-session} \ + "$pkgdir"/usr/share/man/man1/openbox-gnome-session.1 \ + "$pkgdir"/usr/share/xsessions/openbox-gnome.desktop + + sed -i 's:startkde:/usr/bin/\0:' \ + "$pkgdir"/usr/share/xsessions/openbox-kde.desktop + mkdir -p "$pkgdir/etc/$pkgname/samples" + install -Dm644 "${srcdir}/rc.xml" "${pkgdir}/etc/$pkgname/samples/rc.xml" + install -Dm644 "${srcdir}/menu.xml" "${pkgdir}/etc/$pkgname/samples/menu.xml" +} + +install=install diff --git a/clearclick.patch b/clearclick.patch new file mode 100644 index 000000000000..cc506ee79481 --- /dev/null +++ b/clearclick.patch @@ -0,0 +1,68 @@ +diff -urwN -X openbox/.gitignore openbox-efc7efc/Makefile.am openbox/Makefile.am +--- openbox-efc7efc/Makefile.am 2014-12-13 11:53:40.000000000 +0200 ++++ openbox/Makefile.am 2014-12-13 10:21:40.000000000 +0200 +@@ -222,6 +222,7 @@ + openbox/actions/movetoedge.c \ + openbox/actions/omnipresent.c \ + openbox/actions/raise.c \ ++ openbox/actions/clearclick.c \ + openbox/actions/raiselower.c \ + openbox/actions/reconfigure.c \ + openbox/actions/resize.c \ +diff -urwN -X openbox/.gitignore openbox-efc7efc/openbox/actions/all.c openbox/openbox/actions/all.c +--- openbox-efc7efc/openbox/actions/all.c 2014-11-07 19:58:40.000000000 +0200 ++++ openbox/openbox/actions/all.c 2014-12-13 11:58:08.000000000 +0200 +@@ -15,6 +15,7 @@ + action_move_startup(); + action_focus_startup(); + action_raise_startup(); ++ action_clear_click_startup(); + action_lower_startup(); + action_raiselower_startup(); + action_unfocus_startup(); +diff -urwN -X openbox/.gitignore openbox-efc7efc/openbox/actions/all.h openbox/openbox/actions/all.h +--- openbox-efc7efc/openbox/actions/all.h 2014-11-07 19:58:40.000000000 +0200 ++++ openbox/openbox/actions/all.h 2014-12-13 11:57:30.000000000 +0200 +@@ -16,6 +16,7 @@ + void action_move_startup(void); + void action_focus_startup(void); + void action_raise_startup(void); ++void action_clear_click_startup(void); + void action_lower_startup(void); + void action_raiselower_startup(void); + void action_unfocus_startup(void); +diff -urwN -X openbox/.gitignore openbox-efc7efc/openbox/actions/clearclick.c openbox/openbox/actions/clearclick.c +--- openbox-efc7efc/openbox/actions/clearclick.c 1970-01-01 03:00:00.000000000 +0300 ++++ openbox/openbox/actions/clearclick.c 2014-12-13 11:59:15.000000000 +0200 +@@ -0,0 +1,31 @@ ++#include "openbox/actions.h" ++#include "openbox/event.h" ++#include "obt/display.h" ++#include "openbox/focus.h" ++ ++/* This action prevents the transmission of the mouse event ++to the nonactive window. The typical using is ++ ++ <context name="Client"> ++ <mousebind action="Press" button="Left"> ++ <action name="Focus"/> ++ <action name="Raise"/> ++ <action name="ClearClick"/> ++ </mousebind> ++ */ ++ ++static gboolean run_func(ObActionsData *data, gpointer options); ++ ++void action_clear_click_startup(void) ++{ ++ actions_register("ClearClick", NULL, NULL, run_func); ++} ++ ++/* Always return FALSE because its not interactive */ ++static gboolean run_func(ObActionsData *data, gpointer options) ++{ ++ if (data->client && data->client != focus_client) ++ XAllowEvents(obt_display, AsyncPointer , event_time()); ++ ++ return FALSE; ++} diff --git a/clm_w_sub6.patch b/clm_w_sub6.patch new file mode 100644 index 000000000000..3aae888dbb9f --- /dev/null +++ b/clm_w_sub6.patch @@ -0,0 +1,994 @@ +commit 56f62da740419b6edad2cff5f02252bd278d83b0 +Author: Alexey Korop <avkorop@i.ua> +Date: Sun Mar 15 12:22:50 2015 +0200 + + clm_w_sub6.patch + +diff --git a/Makefile.am b/Makefile.am +index f25bf8e..8a3eed6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -241,8 +241,6 @@ openbox_openbox_SOURCES = \ + openbox/client.h \ + openbox/client_list_menu.c \ + openbox/client_list_menu.h \ +- openbox/client_list_combined_menu.c \ +- openbox/client_list_combined_menu.h \ + openbox/client_menu.c \ + openbox/client_menu.h \ + openbox/config.c \ +diff --git a/openbox/client_list_combined_menu.c b/openbox/client_list_combined_menu.c +deleted file mode 100644 +index 84eb506..0000000 +--- a/openbox/client_list_combined_menu.c ++++ /dev/null +@@ -1,167 +0,0 @@ +-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- +- +- client_list_menu.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 "openbox.h" +-#include "menu.h" +-#include "menuframe.h" +-#include "screen.h" +-#include "client.h" +-#include "client_list_combined_menu.h" +-#include "focus.h" +-#include "config.h" +-#include "gettext.h" +- +-#include <glib.h> +- +-#define MENU_NAME "client-list-combined-menu" +- +-static ObMenu *combined_menu; +- +-#define SEPARATOR -1 +-#define ADD_DESKTOP -2 +-#define REMOVE_DESKTOP -3 +- +-static void self_cleanup(ObMenu *menu, gpointer data) +-{ +- menu_clear_entries(menu); +-} +- +-static gboolean self_update(ObMenuFrame *frame, gpointer data) +-{ +- ObMenu *menu = frame->menu; +- ObMenuEntry *e; +- GList *it; +- guint desktop; +- +- menu_clear_entries(menu); +- +- for (desktop = 0; desktop < screen_num_desktops; desktop++) { +- gboolean empty = TRUE; +- gboolean onlyiconic = TRUE; +- +- menu_add_separator(menu, SEPARATOR, screen_desktop_names[desktop]); +- for (it = focus_order; it; it = g_list_next(it)) { +- ObClient *c = it->data; +- if (focus_valid_target(c, desktop, +- TRUE, TRUE, +- FALSE, TRUE, FALSE, FALSE, FALSE)) +- { +- empty = FALSE; +- +- if (c->iconic) { +- gchar *title = g_strdup_printf("(%s)", c->icon_title); +- e = menu_add_normal(menu, desktop, title, NULL, FALSE); +- g_free(title); +- } else { +- onlyiconic = FALSE; +- e = menu_add_normal(menu, desktop, c->title, NULL, FALSE); +- } +- +- if (config_menu_show_icons) { +- e->icon = client_icon(c); +- RrImageRef(e->icon); +- e->icon_alpha = +- c->iconic ? OB_ICONIC_ALPHA : 0xff; +- } +- +- e->data.normal.data = c; +- } +- } +- +- if (empty || onlyiconic) { +- /* no entries or only iconified windows, so add a +- * way to go to this desktop without uniconifying a window */ +- if (!empty) +- menu_add_separator(menu, SEPARATOR, NULL); +- +- e = menu_add_normal(menu, desktop, _("Go there..."), NULL, TRUE); +- if (desktop == screen_desktop) +- e->data.normal.enabled = FALSE; +- } +- } +- +- if (config_menu_manage_desktops) { +- menu_add_separator(menu, SEPARATOR, _("Manage desktops")); +- menu_add_normal(menu, ADD_DESKTOP, _("_Add new desktop"), NULL, TRUE); +- menu_add_normal(menu, REMOVE_DESKTOP, _("_Remove last desktop"), +- NULL, TRUE); +- } +- +- return TRUE; /* always show the menu */ +-} +- +-static void menu_execute(ObMenuEntry *self, ObMenuFrame *f, +- ObClient *c, guint state, gpointer data) +-{ +- if (self->id == ADD_DESKTOP) { +- screen_add_desktop(FALSE); +- menu_frame_hide_all(); +- } +- else if (self->id == REMOVE_DESKTOP) { +- screen_remove_desktop(FALSE); +- menu_frame_hide_all(); +- } +- else { +- ObClient *t = self->data.normal.data; +- if (t) { /* it's set to NULL if its destroyed */ +- gboolean here = state & ShiftMask; +- +- client_activate(t, TRUE, here, TRUE, TRUE, TRUE); +- /* if the window is omnipresent then we need to go to its +- desktop */ +- if (!here && t->desktop == DESKTOP_ALL) +- screen_set_desktop(self->id, FALSE); +- } +- else +- screen_set_desktop(self->id, TRUE); +- } +-} +- +-static void client_dest(ObClient *client, gpointer data) +-{ +- /* This concise function removes all references to a closed +- * client in the client_list_menu, so we don't have to check +- * in client.c */ +- GList *eit; +- for (eit = combined_menu->entries; eit; eit = g_list_next(eit)) { +- ObMenuEntry *meit = eit->data; +- if (meit->type == OB_MENU_ENTRY_TYPE_NORMAL && +- meit->data.normal.data == client) +- { +- meit->data.normal.data = NULL; +- } +- } +-} +- +-void client_list_combined_menu_startup(gboolean reconfig) +-{ +- if (!reconfig) +- client_add_destroy_notify(client_dest, NULL); +- +- combined_menu = menu_new(MENU_NAME, _("Windows"), TRUE, NULL); +- menu_set_update_func(combined_menu, self_update); +- menu_set_cleanup_func(combined_menu, self_cleanup); +- menu_set_execute_func(combined_menu, menu_execute); +-} +- +-void client_list_combined_menu_shutdown(gboolean reconfig) +-{ +- if (!reconfig) +- client_remove_destroy_notify(client_dest); +-} +diff --git a/openbox/client_list_combined_menu.h b/openbox/client_list_combined_menu.h +deleted file mode 100644 +index 420e898..0000000 +--- a/openbox/client_list_combined_menu.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- +- +- client_list_menu.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 ob__client_list_combined_menu_h +-#define ob__client_list_combined_menu_h +- +-void client_list_combined_menu_startup(gboolean reconfig); +-void client_list_combined_menu_shutdown(gboolean reconfig); +- +-#endif +diff --git a/openbox/client_list_menu.c b/openbox/client_list_menu.c +index 4f85935..73f39dc 100644 +--- a/openbox/client_list_menu.c ++++ b/openbox/client_list_menu.c +@@ -21,8 +21,10 @@ + #include "menu.h" + #include "menuframe.h" + #include "screen.h" ++#include "client_menu.h" + #include "client.h" + #include "client_list_menu.h" ++#include "event.h" + #include "focus.h" + #include "config.h" + #include "gettext.h" +@@ -30,68 +32,170 @@ + #include <glib.h> + + #define MENU_NAME "client-list-menu" ++#define COMBINED_MENU_NAME "client-list-combined-menu" ++ ++/* Characters, used as first character of submenu name for ++ actions submenus and move-to submenus. These characters are ++ nonprintable for prevent intersection with user defined names.*/ ++#define ACTIONS_TAG (gchar)1 ++#define SEND_TO_TAG (gchar)2 ++ ++static ObMenu *clients_menu; // visible client list or NULL ++ ++static void clients_list_repaint(ObMenuFrame *f){ ++ guint x,y; ++ ObMenuFrame *p; ++ ObMenuEntryFrame *pe; ++ gchar *name; ++ GravityPoint position = { { 0, }, }; ++ ++ g_assert(f); ++ position.x.pos = f->area.x; ++ position.y.pos = f->area.y; ++ p = f->parent; ++ pe = f->parent_entry; ++ name = g_strdup(f->menu->name); ++ if (config_menu_middle) ++ y += f->area.height / 2; ++ menu_frame_hide(f); ++ if (p) ++ menu_frame_select(p, pe, TRUE); // client-list-menu ++ else ++ menu_show(name, &position, screen_monitor_pointer(), FALSE, FALSE, NULL); // client-list-combined-menu ++ g_free(name); ++} + +-static GSList *desktop_menus; +- +-typedef struct ++static gboolean act_menu_update(ObMenuFrame *frame, gpointer data) + { +- guint desktop; +-} DesktopData; ++ frame->client = frame->menu->data; // simulate the client-menu environment ++ return(client_menu_update(frame, data)); ++} + +-#define SEPARATOR -1 +-#define ADD_DESKTOP -2 +-#define REMOVE_DESKTOP -3 ++static void client_list_cleanup(ObMenu *menu, gpointer data) ++{ ++ clients_menu = NULL; ++} + +-static gboolean desk_menu_update(ObMenuFrame *frame, gpointer data) ++static void client_list_update(ObClient *client, gpointer data) + { +- ObMenu *menu = frame->menu; +- DesktopData *d = data; ++/* This function recreate menu with list of clients ++ if some listed client is closed or moved to the another desktop */ + GList *it; +- gboolean empty = TRUE; +- gboolean onlyiconic = TRUE; ++ ObMenuFrame *f; ++ ++ if (!clients_menu) return; ++ for (it = menu_frame_visible; it; it = g_list_next(it)) { ++ f = it->data; ++ if (f->menu == clients_menu) { ++ clients_list_repaint(f); ++ return; ++ } ++ } ++} + +- menu_clear_entries(menu); ++static void send_to_menu_execute(ObMenuEntry *e, ObMenuFrame *f, ++ ObClient *c, guint state, gpointer data) ++{ ++ g_assert(c); + +- for (it = focus_order; it; it = g_list_next(it)) { +- ObClient *c = it->data; +- if (focus_valid_target(c, d->desktop, +- TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE)) { +- ObMenuEntry *e; ++ client_set_desktop(c, e->id, FALSE, FALSE); ++ client_list_update(c, NULL); ++} + +- empty = FALSE; ++static void add_client_menu(ObMenu *menu, ObClient *c, guint desktop, ++ guint client_number, gboolean *onlyiconic) ++{ ++/* Add submenu for one client "c" to menu "menu". ++ This submenu contains the send-to submenu and action items ++(Activate, Close). ++ Created submenus are never freed directly, they will be freed upon ++next time creation the submenus with the same names, and upon ++openbox termination. ++*/ ++ ObMenuEntry *e; ++ gchar *name; ++ ObMenu* act_menu, *send_to_menu; ++ ++ name = g_strdup_printf("?%d-%d", desktop, client_number); ++ *name = ACTIONS_TAG; ++ if (c->iconic) { ++ gchar *title = g_strdup_printf("(%s)", c->icon_title); ++ act_menu = menu_new(name, title, TRUE, NULL); ++ g_free(title); ++ } else { ++ *onlyiconic = FALSE; ++ act_menu = menu_new(name, c->title, TRUE, NULL); ++ } ++ menu_show_all_shortcuts(act_menu, FALSE); ++ menu_set_update_func(act_menu, act_menu_update); ++ menu_set_execute_func(act_menu, client_menu_execute); ++ act_menu->data = c; // for act_menu_update ++ ++ *name = SEND_TO_TAG; // send-to menu name ++ send_to_menu = client_menu_send_to_menu_new(name); ++ menu_set_execute_func(send_to_menu, send_to_menu_execute); ++ ++ menu_add_submenu(act_menu, CLIENT_SEND_TO, name); ++ e = menu_add_normal(act_menu, CLIENT_ACTIVATE, _("_Activate"), NULL, TRUE); ++ e->data.normal.data = (gpointer)desktop; // see CLIENT_ACTIVATE in client_menu_execute ++ act_menu->default_entry = e; ++ client_menu_add_actions(act_menu, CA_CLOSE); ++ ++ *name = ACTIONS_TAG; ++ e = menu_add_submenu(menu, desktop, name); ++ g_free(name); ++ if (config_menu_show_icons) { ++ e->icon = client_icon(c); ++ RrImageRef(e->icon); ++ e->icon_alpha = ++ c->iconic ? OB_ICONIC_ALPHA : 0xff; ++ menu_set_cleanup_func(menu, client_list_cleanup); ++ clients_menu = menu; ++ } ++} + +- if (c->iconic) { +- gchar *title = g_strdup_printf("(%s)", c->icon_title); +- e = menu_add_normal(menu, d->desktop, title, NULL, FALSE); +- g_free(title); +- } else { +- onlyiconic = FALSE; +- e = menu_add_normal(menu, d->desktop, c->title, NULL, FALSE); +- } +- +- if (config_menu_show_icons) { +- e->icon = client_icon(c); +- RrImageRef(e->icon); +- e->icon_alpha = c->iconic ? OB_ICONIC_ALPHA : 0xff; +- } +- +- e->data.normal.data = c; ++/* Add all items about one desktop to the menu */ ++void add_clients(ObMenu *menu, guint desktop) ++{ ++ ObMenuEntry *e; ++ GList *it; ++ gboolean empty = TRUE; ++ gboolean onlyiconic = TRUE; ++ guint client_number = 0; ++ ObClient *c; ++ ++ for (it = focus_order; it; it = g_list_next(it)) ++ { ++ c = it->data; ++ if (focus_valid_target(c, desktop, ++ TRUE, TRUE, ++ FALSE, TRUE, FALSE, FALSE, FALSE)) ++ { ++ empty = FALSE; ++ add_client_menu(menu, c, desktop, client_number, &onlyiconic); + } ++ ++client_number; + } + + if (empty || onlyiconic) { +- ObMenuEntry *e; +- + /* no entries or only iconified windows, so add a + * way to go to this desktop without uniconifying a window */ + if (!empty) + menu_add_separator(menu, SEPARATOR, NULL); + +- e = menu_add_normal(menu, d->desktop, _("Go there..."), NULL, TRUE); +- if (d->desktop == screen_desktop) ++ e = menu_add_normal(menu, desktop, _("Go there..."), NULL, TRUE); ++ if (desktop == screen_desktop) + e->data.normal.enabled = FALSE; ++ menu_find_submenus(menu); // for client_list_update + } ++} ++ ++static gboolean desk_menu_update(ObMenuFrame *frame, gpointer data) ++{ ++ ObMenu *menu = frame->menu; + ++ menu_clear_entries(menu); ++ add_clients(menu, (guint)data); + return TRUE; /* always show */ + } + +@@ -99,6 +203,7 @@ static void desk_menu_execute(ObMenuEntry *self, ObMenuFrame *f, + ObClient *c, guint state, gpointer data) + { + ObClient *t = self->data.normal.data; ++ + if (t) { /* it's set to NULL if its destroyed */ + gboolean here = state & ShiftMask; + +@@ -108,70 +213,41 @@ static void desk_menu_execute(ObMenuEntry *self, ObMenuFrame *f, + if (!here && t->desktop == DESKTOP_ALL) + screen_set_desktop(self->id, FALSE); + } +- else ++ else // this case used in client-list-menu only + screen_set_desktop(self->id, TRUE); + } + +-static void desk_menu_destroy(ObMenu *menu, gpointer data) +-{ +- DesktopData *d = data; +- +- g_slice_free(DesktopData, d); +- +- desktop_menus = g_slist_remove(desktop_menus, menu); +-} +- +-static void self_cleanup(ObMenu *menu, gpointer data) +-{ +- menu_clear_entries(menu); +- +- while (desktop_menus) { +- menu_free(desktop_menus->data); +- desktop_menus = g_slist_delete_link(desktop_menus, desktop_menus); ++void add_desktop_manage(ObMenu *menu){ ++ if (config_menu_manage_desktops) { ++ menu_add_separator(menu, SEPARATOR, NULL); ++ menu_add_normal(menu, ADD_DESKTOP, _("_Add new desktop"), NULL, TRUE); ++ menu_add_normal(menu, REMOVE_DESKTOP, _("_Remove last desktop"), ++ NULL, TRUE); + } + } + +-static gboolean self_update(ObMenuFrame *frame, gpointer data) ++static gboolean client_list_menu_update(ObMenuFrame *frame, gpointer data) + { + ObMenu *menu = frame->menu; + guint i; + + menu_clear_entries(menu); + +- while (desktop_menus) { +- menu_free(desktop_menus->data); +- desktop_menus = g_slist_delete_link(desktop_menus, desktop_menus); +- } +- + for (i = 0; i < screen_num_desktops; ++i) { +- ObMenu *submenu; ++ ObMenu *desktop_menu; + gchar *name = g_strdup_printf("%s-%u", MENU_NAME, i); +- DesktopData *ddata = g_slice_new(DesktopData); +- +- ddata->desktop = i; +- submenu = menu_new(name, screen_desktop_names[i], FALSE, ddata); +- menu_set_update_func(submenu, desk_menu_update); +- menu_set_execute_func(submenu, desk_menu_execute); +- menu_set_destroy_func(submenu, desk_menu_destroy); +- ++ desktop_menu = menu_new(name, screen_desktop_names[i], FALSE, (gpointer)i); ++ menu_set_update_func(desktop_menu, desk_menu_update); ++ menu_set_execute_func(desktop_menu, desk_menu_execute); + menu_add_submenu(menu, i, name); + + g_free(name); +- +- desktop_menus = g_slist_append(desktop_menus, submenu); +- } +- +- if (config_menu_manage_desktops) { +- menu_add_separator(menu, SEPARATOR, NULL); +- menu_add_normal(menu, ADD_DESKTOP, _("_Add new desktop"), NULL, TRUE); +- menu_add_normal(menu, REMOVE_DESKTOP, _("_Remove last desktop"), +- NULL, TRUE); + } +- ++ add_desktop_manage(menu); + return TRUE; /* always show */ + } + +-static void self_execute(ObMenuEntry *self, ObMenuFrame *f, ++static void root_menu_execute(ObMenuEntry *self, ObMenuFrame *f, + ObClient *c, guint state, gpointer data) + { + if (self->id == ADD_DESKTOP) { +@@ -182,26 +258,8 @@ static void self_execute(ObMenuEntry *self, ObMenuFrame *f, + screen_remove_desktop(FALSE); + menu_frame_hide_all(); + } +-} +- +-static void client_dest(ObClient *client, gpointer data) +-{ +- /* This concise function removes all references to a closed +- * client in the client_list_menu, so we don't have to check +- * in client.c */ +- GSList *it; +- for (it = desktop_menus; it; it = g_slist_next(it)) { +- ObMenu *mit = it->data; +- GList *eit; +- for (eit = mit->entries; eit; eit = g_list_next(eit)) { +- ObMenuEntry *meit = eit->data; +- if (meit->type == OB_MENU_ENTRY_TYPE_NORMAL && +- meit->data.normal.data == client) +- { +- meit->data.normal.data = NULL; +- } +- } +- } ++ else // this case used in client-list-combined-menu only ++ screen_set_desktop(self->id, TRUE); + } + + void client_list_menu_startup(gboolean reconfig) +@@ -209,16 +267,40 @@ void client_list_menu_startup(gboolean reconfig) + ObMenu *menu; + + if (!reconfig) +- client_add_destroy_notify(client_dest, NULL); ++ client_add_destroy_notify(client_list_update, NULL); + + menu = menu_new(MENU_NAME, _("Desktops"), TRUE, NULL); +- menu_set_update_func(menu, self_update); +- menu_set_cleanup_func(menu, self_cleanup); +- menu_set_execute_func(menu, self_execute); ++ menu_set_update_func(menu, client_list_menu_update); ++ menu_set_execute_func(menu, root_menu_execute); + } + + void client_list_menu_shutdown(gboolean reconfig) + { + if (!reconfig) +- client_remove_destroy_notify(client_dest); ++ client_remove_destroy_notify(client_list_update); ++} ++ ++static gboolean combined_menu_update(ObMenuFrame *frame, gpointer data) ++{ ++ ObMenu *menu = frame->menu; ++ guint desktop; ++ ++ menu_clear_entries(menu); ++ ++ for (desktop = 0; desktop < screen_num_desktops; desktop++) { ++ menu_add_separator(menu, SEPARATOR, screen_desktop_names[desktop]); ++ add_clients(menu, desktop); ++ } ++ add_desktop_manage(menu); ++ menu_find_submenus(menu); // for client_list_update ++ return TRUE; /* always show the menu */ ++} ++ ++void client_list_combined_menu_startup(gboolean reconfig) ++{ ++ ObMenu *combined_menu; ++ ++ combined_menu = menu_new(COMBINED_MENU_NAME, _("Windows"), TRUE, NULL); ++ menu_set_update_func(combined_menu, combined_menu_update); ++ menu_set_execute_func(combined_menu, root_menu_execute); + } +diff --git a/openbox/client_list_menu.h b/openbox/client_list_menu.h +index 860cd50..b67c95f 100644 +--- a/openbox/client_list_menu.h ++++ b/openbox/client_list_menu.h +@@ -20,7 +20,13 @@ + #ifndef ob__client_list_menu_h + #define ob__client_list_menu_h + ++#define SEPARATOR -1 ++#define ADD_DESKTOP -2 ++#define REMOVE_DESKTOP -3 ++ + void client_list_menu_startup(gboolean reconfig); + void client_list_menu_shutdown(gboolean reconfig); +- ++void client_list_add_clients(ObMenu *menu, guint desktop); ++void client_list_add_desktop_manage(ObMenu *menu); ++void client_list_combined_menu_startup(gboolean reconfig); + #endif +diff --git a/openbox/client_menu.c b/openbox/client_menu.c +index 6d5c4c7..e48d810 100644 +--- a/openbox/client_menu.c ++++ b/openbox/client_menu.c +@@ -42,21 +42,9 @@ enum { + LAYER_BOTTOM = -1 + }; + +-enum { +- CLIENT_SEND_TO, +- CLIENT_LAYER, +- CLIENT_ICONIFY, +- CLIENT_RESTORE, +- CLIENT_MAXIMIZE, +- CLIENT_SHADE, +- CLIENT_DECORATE, +- CLIENT_MOVE, +- CLIENT_RESIZE, +- CLIENT_CLOSE +-}; +- +-static void set_icon_color(ObMenuEntry *e) ++static void menu_entry_set_mask(ObMenuEntry *e, RrPixmapMask *mask) + { ++ e->mask = mask; + e->mask_normal_color = ob_rr_theme->menu_color; + e->mask_selected_color = ob_rr_theme->menu_selected_color; + e->mask_disabled_color = ob_rr_theme->menu_disabled_color; +@@ -64,7 +52,7 @@ static void set_icon_color(ObMenuEntry *e) + ob_rr_theme->menu_disabled_selected_color; + } + +-static gboolean client_menu_update(ObMenuFrame *frame, gpointer data) ++gboolean client_menu_update(ObMenuFrame *frame, gpointer data) + { + ObMenu *menu = frame->menu; + GList *it; +@@ -112,11 +100,12 @@ static gboolean client_menu_update(ObMenuFrame *frame, gpointer data) + return TRUE; /* show the menu */ + } + +-static void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f, ++void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f, + ObClient *c, guint state, gpointer data) + { + gint x, y; + gulong ignore_start; ++ gboolean here; + + if (!c) + return; +@@ -165,6 +154,14 @@ static void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f, + case CLIENT_CLOSE: + client_close(c); + break; ++ case CLIENT_ACTIVATE: // for client list (combined) menu ++ here = state & ShiftMask; ++ client_activate(c, TRUE, here, TRUE, TRUE, TRUE); ++ /* if the window is omnipresent then we need to go to its ++ desktop */ ++ if (!here && c->desktop == DESKTOP_ALL) ++ screen_set_desktop((gint)e->data.normal.data, FALSE); ++ break; + default: + g_assert_not_reached(); + } +@@ -233,7 +230,7 @@ static void layer_menu_execute(ObMenuEntry *e, ObMenuFrame *f, + } + } + +-static gboolean send_to_menu_update(ObMenuFrame *frame, gpointer data) ++static gboolean client_menu_send_to_menu_update(ObMenuFrame *frame, gpointer data) + { + ObMenu *menu = frame->menu; + ObClient *c = frame->client; +@@ -267,18 +264,21 @@ static gboolean send_to_menu_update(ObMenuFrame *frame, gpointer data) + } + } + ++ menu->default_entry = NULL; + for (it = menu->entries; it; it = g_list_next(it)) { + ObMenuEntry *e = it->data; + guint desk = e->id; + + e->data.normal.enabled = c->desktop != desk; ++ if (e->data.normal.enabled && (desk == screen_desktop)) ++ { // mark this desktop target as the default item ++ menu->default_entry = e; ++ } + + if ((desk == DESKTOP_ALL && c->desktop != DESKTOP_ALL) || + (c->desktop == DESKTOP_ALL && desk == screen_desktop)) +- { +- e->mask = ob_rr_theme->btn_desk->unpressed_mask; +- set_icon_color(e); +- } else ++ menu_entry_set_mask(e, ob_rr_theme->btn_desk->unpressed_mask); ++ else + e->mask = NULL; + } + +@@ -295,7 +295,7 @@ static void send_to_menu_execute(ObMenuEntry *e, ObMenuFrame *f, + /* the client won't even be on the screen anymore, so hide the menu */ + menu_frame_hide_all(); + else if (f) { +- send_to_menu_update(f, (gpointer)1); ++ client_menu_send_to_menu_update(f, (gpointer)1); + menu_frame_render(f); + } + } +@@ -363,10 +363,59 @@ static void client_menu_place(ObMenuFrame *frame, gint *x, gint *y, + } + } + ++void client_menu_add_actions(ObMenu *menu, guint ca_mask) ++{ ++ ObMenuEntry *e; ++ ++ if (ca_mask & CA_RESTORE){ ++ e = menu_add_normal(menu, CLIENT_RESTORE, _("R_estore"), NULL, TRUE); ++ menu_entry_set_mask(e, ob_rr_theme->btn_max->unpressed_toggled_mask); ++ } ++ if (ca_mask & CA_MOVE) ++ menu_add_normal(menu, CLIENT_MOVE, _("_Move"), NULL, TRUE); ++ ++ if (ca_mask & CA_RESIZE) ++ menu_add_normal(menu, CLIENT_RESIZE, _("Resi_ze"), NULL, TRUE); ++ ++ if (ca_mask & CA_ICONIFY){ ++ e = menu_add_normal(menu, CLIENT_ICONIFY, _("Ico_nify"), NULL, TRUE); ++ menu_entry_set_mask(e, ob_rr_theme->btn_iconify->unpressed_mask); ++ } ++ ++ if (ca_mask & CA_MAXIMIZE){ ++ e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Ma_ximize"), NULL, TRUE); ++ menu_entry_set_mask(e, ob_rr_theme->btn_max->unpressed_mask); ++ } ++ ++ if (ca_mask & CA_SHADE){ ++ e = menu_add_normal(menu, CLIENT_SHADE, _("_Roll up/down"), NULL, TRUE); ++ menu_entry_set_mask(e, ob_rr_theme->btn_shade->unpressed_mask); ++ } ++ ++ if (ca_mask & CA_DECORATE) ++ menu_add_normal(menu, CLIENT_DECORATE, _("Un/_Decorate"), NULL, TRUE); ++ ++ if (ca_mask & CA_CLOSE){ ++ menu_add_separator(menu, -1, NULL); ++ e = menu_add_normal(menu, CLIENT_CLOSE, _("_Close"), NULL, TRUE); ++ menu_entry_set_mask(e, ob_rr_theme->btn_close->unpressed_mask); ++ } ++} ++ ++ObMenu *client_menu_send_to_menu_new(gchar *name){ ++ ObMenu *menu; ++ ++ menu = menu_new(name, _("_Send to desktop"), TRUE, NULL); ++ menu_set_update_func(menu, client_menu_send_to_menu_update); ++ return(menu); ++} ++ + void client_menu_startup(void) + { ++ guint const ca_client = CA_SEND_TO | CA_LAYER | CA_ICONIFY | ++ CA_RESTORE | CA_MAXIMIZE | CA_SHADE | CA_DECORATE | ++ CA_MOVE | CA_RESIZE | CA_CLOSE; + ObMenu *menu; +- ObMenuEntry *e; + + menu = menu_new(LAYER_MENU_NAME, _("_Layer"), TRUE, NULL); + menu_show_all_shortcuts(menu, TRUE); +@@ -377,8 +426,7 @@ void client_menu_startup(void) + menu_add_normal(menu, LAYER_NORMAL, _("_Normal"), NULL, TRUE); + menu_add_normal(menu, LAYER_BOTTOM, _("Always on _bottom"),NULL, TRUE); + +- menu = menu_new(SEND_TO_MENU_NAME, _("_Send to desktop"), TRUE, NULL); +- menu_set_update_func(menu, send_to_menu_update); ++ menu = client_menu_send_to_menu_new(SEND_TO_MENU_NAME); + menu_set_execute_func(menu, send_to_menu_execute); + + menu = menu_new(CLIENT_MENU_NAME, _("Client menu"), TRUE, NULL); +@@ -390,32 +438,5 @@ void client_menu_startup(void) + menu_add_submenu(menu, CLIENT_SEND_TO, SEND_TO_MENU_NAME); + + menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME); +- +- e = menu_add_normal(menu, CLIENT_RESTORE, _("R_estore"), NULL, TRUE); +- e->mask = ob_rr_theme->btn_max->unpressed_toggled_mask; +- set_icon_color(e); +- +- menu_add_normal(menu, CLIENT_MOVE, _("_Move"), NULL, TRUE); +- +- menu_add_normal(menu, CLIENT_RESIZE, _("Resi_ze"), NULL, TRUE); +- +- e = menu_add_normal(menu, CLIENT_ICONIFY, _("Ico_nify"), NULL, TRUE); +- e->mask = ob_rr_theme->btn_iconify->unpressed_mask; +- set_icon_color(e); +- +- e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Ma_ximize"), NULL, TRUE); +- e->mask = ob_rr_theme->btn_max->unpressed_mask; +- set_icon_color(e); +- +- e = menu_add_normal(menu, CLIENT_SHADE, _("_Roll up/down"), NULL, TRUE); +- e->mask = ob_rr_theme->btn_shade->unpressed_mask; +- set_icon_color(e); +- +- menu_add_normal(menu, CLIENT_DECORATE, _("Un/_Decorate"), NULL, TRUE); +- +- menu_add_separator(menu, -1, NULL); +- +- e = menu_add_normal(menu, CLIENT_CLOSE, _("_Close"), NULL, TRUE); +- e->mask = ob_rr_theme->btn_close->unpressed_mask; +- set_icon_color(e); ++ client_menu_add_actions(menu, ca_client); + } +diff --git a/openbox/client_menu.h b/openbox/client_menu.h +index 5c55516..2c16334 100644 +--- a/openbox/client_menu.h ++++ b/openbox/client_menu.h +@@ -18,7 +18,38 @@ + + #ifndef ob__client_menu_h + #define ob__client_menu_h ++#include "client.h" + +-void client_menu_startup(void); ++enum { ++ CLIENT_SEND_TO, ++ CLIENT_LAYER, ++ CLIENT_ICONIFY, ++ CLIENT_RESTORE, ++ CLIENT_MAXIMIZE, ++ CLIENT_SHADE, ++ CLIENT_DECORATE, ++ CLIENT_MOVE, ++ CLIENT_RESIZE, ++ CLIENT_CLOSE, ++ CLIENT_ACTIVATE ++}; ++ ++// client actions bits for menu creation mask ++#define CA_SEND_TO (1<<CLIENT_SEND_TO) ++#define CA_LAYER (1<<CLIENT_LAYER) ++#define CA_ICONIFY (1<<CLIENT_ICONIFY) ++#define CA_RESTORE (1<<CLIENT_RESTORE) ++#define CA_MAXIMIZE (1<<CLIENT_MAXIMIZE) ++#define CA_SHADE (1<<CLIENT_SHADE) ++#define CA_DECORATE (1<<CLIENT_DECORATE) ++#define CA_MOVE (1<<CLIENT_MOVE) ++#define CA_RESIZE (1<<CLIENT_RESIZE) ++#define CA_CLOSE (1<<CLIENT_CLOSE) + ++void client_menu_startup(void); ++gboolean client_menu_update(ObMenuFrame *frame, gpointer data); ++void client_menu_add_actions(ObMenu *menu, guint ca_mask); ++ObMenu *client_menu_send_to_menu_new(gchar *name); ++void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f, ++ ObClient *c, guint state, gpointer data); + #endif +diff --git a/openbox/menu.c b/openbox/menu.c +index 6c0cf7e..48c95e2 100644 +--- a/openbox/menu.c ++++ b/openbox/menu.c +@@ -32,7 +32,6 @@ + #include "misc.h" + #include "client_menu.h" + #include "client_list_menu.h" +-#include "client_list_combined_menu.h" + #include "gettext.h" + #include "obt/xml.h" + #include "obt/paths.h" +@@ -126,7 +125,6 @@ void menu_shutdown(gboolean reconfig) + + menu_frame_hide_all(); + +- client_list_combined_menu_shutdown(reconfig); + client_list_menu_shutdown(reconfig); + + g_hash_table_destroy(menu_hash); +diff --git a/openbox/menuframe.c b/openbox/menuframe.c +index 943ff69..81a55ba 100644 +--- a/openbox/menuframe.c ++++ b/openbox/menuframe.c +@@ -56,7 +56,6 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, + static void menu_entry_frame_free(ObMenuEntryFrame *self); + static void menu_frame_update(ObMenuFrame *self); + static gboolean submenu_show_timeout(gpointer data); +-static void menu_frame_hide(ObMenuFrame *self); + + static gboolean submenu_hide_timeout(gpointer data); + +@@ -1130,7 +1129,7 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, + return TRUE; + } + +-static void menu_frame_hide(ObMenuFrame *self) ++void menu_frame_hide(ObMenuFrame *self) + { + ObMenu *const menu = self->menu; + GList *it = g_list_find(menu_frame_visible, self); +diff --git a/openbox/menuframe.h b/openbox/menuframe.h +index ffcedf6..123cadf 100644 +--- a/openbox/menuframe.h ++++ b/openbox/menuframe.h +@@ -129,6 +129,7 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, const GravityPoint *pos, + gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, + ObMenuEntryFrame *parent_entry); + ++void menu_frame_hide(ObMenuFrame *self); + void menu_frame_hide_all(void); + void menu_frame_hide_all_client(struct _ObClient *client); + +diff --git a/po/POTFILES.in b/po/POTFILES.in +index 4509714..decb09e 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -3,7 +3,6 @@ openbox/actions.c + openbox/actions/execute.c + openbox/actions/exit.c + openbox/client.c +-openbox/client_list_combined_menu.c + openbox/client_list_menu.c + openbox/client_menu.c + openbox/config.c +diff --git a/po/openbox.pot b/po/openbox.pot +index 3e5a5a9..aafc288 100644 +--- a/po/openbox.pot ++++ b/po/openbox.pot +@@ -451,3 +451,6 @@ msgstr "" + #: openbox/prompt.c:154 + msgid "OK" + msgstr "" ++ ++msgid "_Activate" ++msgstr "" +diff --git a/po/ru.po b/po/ru.po +index 62424a3..ccbcb91 100644 +--- a/po/ru.po ++++ b/po/ru.po +@@ -471,3 +471,6 @@ msgstr "Запрошенного ключа \"%s\" на экране не сущ + #: openbox/prompt.c:154 + msgid "OK" + msgstr "OK" ++ ++msgid "_Activate" ++msgstr "Активизировать (_A)" +diff --git a/po/uk.po b/po/uk.po +index 9d300ef..3642b63 100644 +--- a/po/uk.po ++++ b/po/uk.po +@@ -474,3 +474,6 @@ msgstr "Потрібної кнопки \"%s\" нема на екрані" + #: openbox/prompt.c:154 + msgid "OK" + msgstr "Гаразд" ++ ++msgid "_Activate" ++msgstr "Активізувати (_A)" diff --git a/compact_menu.patch b/compact_menu.patch new file mode 100644 index 000000000000..e5c5296bd2bd --- /dev/null +++ b/compact_menu.patch @@ -0,0 +1,12 @@ +diff --git a/openbox/menuframe.c b/openbox/menuframe.c +--- a/openbox/menuframe.c ++++ b/openbox/menuframe.c +@@ -31,7 +31,7 @@ + #include "obt/display.h" + #include "obrender/theme.h" + +-#define PADDING 2 ++#define PADDING 0 + #define MAX_MENU_WIDTH 400 + + #define ITEM_HEIGHT (ob_rr_theme->menu_font_height + 2*PADDING) diff --git a/disable_edges_by_default.patch b/disable_edges_by_default.patch new file mode 100644 index 000000000000..3bff76d0377e --- /dev/null +++ b/disable_edges_by_default.patch @@ -0,0 +1,55 @@ +diff --git a/openbox/config.c b/openbox/config.c +--- a/openbox/config.c ++++ b/openbox/config.c +@@ -27,6 +27,7 @@ + #include "openbox.h" + #include "gettext.h" + #include "obt/paths.h" ++#include "edges.h" + + gboolean config_focus_new; + gboolean config_focus_follow; +@@ -565,6 +566,7 @@ static void parse_mouse(xmlNodePtr node, gpointer d) + } + continue; + } ++ enable_edge(cx - OB_FRAME_CONTEXT_EDGE_TOP); + + nbut = obt_xml_find_node(n->children, "mousebind"); + while (nbut) { +diff --git a/openbox/edges.c b/openbox/edges.c +index 2b40619..2aea791 100644 +--- a/openbox/edges.c ++++ b/openbox/edges.c +@@ -10,7 +10,7 @@ + /* Array of array of monitors of edges: edge[monitor 2][top edge] */ + ObEdge ***edge = NULL; + #warning put in config.c and parse configs of course +-gboolean config_edge_enabled[OB_NUM_EDGES] = {1, 1, 1, 1, 1, 1, 1, 1}; ++gboolean config_edge_enabled[OB_NUM_EDGES] = {0, 0, 0, 0, 0, 0, 0, 0}; + /* this could change at runtime, we should hook into that, but for now + * don't crash on reconfigure/shutdown */ + static guint edge_monitors; +@@ -133,3 +133,10 @@ void edges_configure() + edges_shutdown(TRUE); + edges_startup(TRUE); + } ++ ++void enable_edge(int may_be_edge_index) ++{ ++ if ((may_be_edge_index >= 0) && (may_be_edge_index < OB_NUM_EDGES)) ++ config_edge_enabled[may_be_edge_index] = 1; ++ ++} +diff --git a/openbox/edges.h b/openbox/edges.h +index 419cba6..1070e9f 100644 +--- a/openbox/edges.h ++++ b/openbox/edges.h +@@ -25,6 +25,7 @@ struct _ObEdge + ObEdgeLocation location; + }; + ++void enable_edge(int may_be_edge_index); + void edges_startup(gboolean reconfigure); + void edges_shutdown(gboolean reconfigure); + void edges_configure(void); diff --git a/edge_mikabox.patch b/edge_mikabox.patch new file mode 100644 index 000000000000..3bd0180c5a03 --- /dev/null +++ b/edge_mikabox.patch @@ -0,0 +1,396 @@ +diff -urN /mnt/i/linux/openbox/openbox/Makefile.am ./Makefile.am +--- /mnt/i/linux/openbox/openbox/Makefile.am 2014-12-25 11:21:03.000000000 +0200 ++++ ./Makefile.am 2015-01-12 21:04:16.301754384 +0200 +@@ -247,6 +247,8 @@ + openbox/debug.h \ + openbox/dock.c \ + openbox/dock.h \ ++ openbox/edges.c \ ++ openbox/edges.h \ + openbox/event.c \ + openbox/event.h \ + openbox/focus.c \ +diff -urN /mnt/i/linux/openbox/openbox/openbox/edges.c ./openbox/edges.c +--- /mnt/i/linux/openbox/openbox/openbox/edges.c 1970-01-01 03:00:00.000000000 +0300 ++++ ./openbox/edges.c 2015-01-12 21:04:26.662753953 +0200 +@@ -0,0 +1,135 @@ ++#include "openbox.h" ++#include "config.h" ++#include "screen.h" ++#include "edges.h" ++#include "frame.h" ++ ++#include <X11/Xlib.h> ++#include <glib.h> ++ ++/* Array of array of monitors of edges: edge[monitor 2][top edge] */ ++ObEdge ***edge = NULL; ++#warning put in config.c and parse configs of course ++gboolean config_edge_enabled[OB_NUM_EDGES] = {1, 1, 1, 1, 1, 1, 1, 1}; ++/* this could change at runtime, we should hook into that, but for now ++ * don't crash on reconfigure/shutdown */ ++static guint edge_monitors; ++ ++#ifdef DEBUG ++#define EDGE_WIDTH 10 ++#define CORNER_SIZE 20 ++#else ++#define EDGE_WIDTH 1 ++#define CORNER_SIZE 2 ++#endif ++static void get_position(ObEdgeLocation edge, Rect screen, Rect *rect) ++{ ++ switch (edge) { ++ case OB_EDGE_TOP: ++ RECT_SET(*rect, CORNER_SIZE, 0, ++ screen.width - 2 * CORNER_SIZE, EDGE_WIDTH); ++ break; ++ case OB_EDGE_TOPRIGHT: ++ RECT_SET(*rect, screen.width - CORNER_SIZE, 0, ++ CORNER_SIZE, CORNER_SIZE); ++ break; ++ case OB_EDGE_RIGHT: ++ RECT_SET(*rect, screen.width - EDGE_WIDTH, CORNER_SIZE, ++ EDGE_WIDTH, screen.height - 2 * CORNER_SIZE); ++ break; ++ case OB_EDGE_BOTTOMRIGHT: ++ RECT_SET(*rect, screen.width - CORNER_SIZE, ++ screen.height - CORNER_SIZE, ++ CORNER_SIZE, CORNER_SIZE); ++ break; ++ case OB_EDGE_BOTTOM: ++ RECT_SET(*rect, CORNER_SIZE, screen.height - EDGE_WIDTH, ++ screen.width - 2 * CORNER_SIZE, EDGE_WIDTH); ++ break; ++ case OB_EDGE_BOTTOMLEFT: ++ RECT_SET(*rect, 0, screen.height - CORNER_SIZE, ++ CORNER_SIZE, CORNER_SIZE); ++ break; ++ case OB_EDGE_LEFT: ++ RECT_SET(*rect, 0, CORNER_SIZE, ++ EDGE_WIDTH, screen.height - 2 * CORNER_SIZE); ++ break; ++ case OB_EDGE_TOPLEFT: ++ RECT_SET(*rect, 0, 0, CORNER_SIZE, CORNER_SIZE); ++ break; ++ } ++ rect[0].x += screen.x; ++ rect[0].y += screen.y; ++} ++ ++void edges_startup(gboolean reconfigure) ++{ ++ ObEdgeLocation i; ++ gint m; ++ Rect r; ++ XSetWindowAttributes xswa; ++ ++ xswa.override_redirect = True; ++ ++ edge_monitors = screen_num_monitors; ++ ++ edge = g_slice_alloc(sizeof(ObEdge**) * edge_monitors); ++ for (m = 0; m < edge_monitors; m++) { ++ const Rect *monitor = screen_physical_area_monitor(m); ++ edge[m] = g_slice_alloc(sizeof(ObEdge*) * OB_NUM_EDGES); ++ for (i=0; i < OB_NUM_EDGES; i++) { ++ if (!config_edge_enabled[i]) ++ continue; ++ ++ edge[m][i] = g_slice_new(ObEdge); ++ edge[m][i]->obwin.type = OB_WINDOW_CLASS_EDGE; ++ edge[m][i]->location = i; ++ ++ get_position(i, *monitor, &r); ++ edge[m][i]->win = XCreateWindow(obt_display, obt_root(ob_screen), ++ r.x, r.y, r.width, r.height, 0, 0, InputOnly, ++ CopyFromParent, CWOverrideRedirect, &xswa); ++ XSelectInput(obt_display, edge[m][i]->win, ButtonPressMask | ButtonReleaseMask ++ | EnterWindowMask | LeaveWindowMask); ++ XMapWindow(obt_display, edge[m][i]->win); ++ ++ stacking_add(EDGE_AS_WINDOW(edge[m][i])); ++ window_add(&edge[m][i]->win, EDGE_AS_WINDOW(edge[m][i])); ++ ++#ifdef DEBUG ++ ob_debug("mapped edge window %i at %03i %03i %02i %02i", i, r.x, r.y, r.width, r.height); ++#endif ++ } ++ } ++ ++ XFlush(obt_display); ++} ++ ++void edges_shutdown(gboolean reconfigure) ++{ ++ gint i, m; ++ ++ /* This is in case we get called before startup by screen_resize() */ ++ if (!edge) ++ return; ++ ++ for (m = 0; m < edge_monitors; m++) { ++ for (i = 0; i < OB_NUM_EDGES; i++) { ++ if (!config_edge_enabled[i]) ++ continue; ++ ++ window_remove(edge[m][i]->win); ++ stacking_remove(EDGE_AS_WINDOW(edge[m][i])); ++ XDestroyWindow(obt_display, edge[m][i]->win); ++ g_slice_free(ObEdge, edge[m][i]); ++ } ++ g_slice_free1(sizeof(ObEdge*) * OB_NUM_EDGES, edge[m]); ++ } ++ g_slice_free1(sizeof(ObEdge**) * edge_monitors, edge); ++} ++ ++void edges_configure() ++{ ++ edges_shutdown(TRUE); ++ edges_startup(TRUE); ++} +diff -urN /mnt/i/linux/openbox/openbox/openbox/edges.h ./openbox/edges.h +--- /mnt/i/linux/openbox/openbox/openbox/edges.h 1970-01-01 03:00:00.000000000 +0300 ++++ ./openbox/edges.h 2015-01-12 21:04:26.664753953 +0200 +@@ -0,0 +1,32 @@ ++#ifndef __edges_h ++#define __edges_h ++ ++#include "window.h" ++ ++typedef enum ++{ ++ OB_EDGE_TOP, ++ OB_EDGE_TOPRIGHT, ++ OB_EDGE_RIGHT, ++ OB_EDGE_BOTTOMRIGHT, ++ OB_EDGE_BOTTOM, ++ OB_EDGE_BOTTOMLEFT, ++ OB_EDGE_LEFT, ++ OB_EDGE_TOPLEFT, ++ OB_NUM_EDGES ++} ObEdgeLocation; ++ ++typedef struct _ObEdge ObEdge; ++ ++struct _ObEdge ++{ ++ ObWindow obwin; ++ Window win; ++ ObEdgeLocation location; ++}; ++ ++void edges_startup(gboolean reconfigure); ++void edges_shutdown(gboolean reconfigure); ++void edges_configure(void); ++ ++#endif +diff -urN /mnt/i/linux/openbox/openbox/openbox/event.c ./openbox/event.c +--- /mnt/i/linux/openbox/openbox/openbox/event.c 2014-12-25 11:17:52.000000000 +0200 ++++ ./openbox/event.c 2015-01-12 21:04:16.302754384 +0200 +@@ -30,6 +30,7 @@ + #include "grab.h" + #include "menu.h" + #include "prompt.h" ++#include "edges.h" + #include "menuframe.h" + #include "keyboard.h" + #include "mouse.h" +@@ -479,9 +480,6 @@ + case OB_WINDOW_CLASS_MENUFRAME: + menu = WINDOW_AS_MENUFRAME(obwin); + break; +- case OB_WINDOW_CLASS_INTERNAL: +- /* we don't do anything with events directly on these windows */ +- break; + case OB_WINDOW_CLASS_PROMPT: + prompt = WINDOW_AS_PROMPT(obwin); + break; +@@ -710,7 +708,7 @@ + /* ...or it if it was physically on an openbox + internal window... */ + ((w = window_find(e->xbutton.subwindow)) && +- (WINDOW_IS_INTERNAL(w) || WINDOW_IS_DOCK(w)))) ++ (WINDOW_IS_INTERNAL(w) || WINDOW_IS_DOCK(w) || WINDOW_IS_EDGE(w)))) + /* ...then process the event, otherwise ignore it */ + { + used = event_handle_user_input(client, e); +diff -urN /mnt/i/linux/openbox/openbox/openbox/frame.c ./openbox/frame.c +--- /mnt/i/linux/openbox/openbox/openbox/frame.c 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/frame.c 2015-01-12 21:04:16.302754384 +0200 +@@ -28,6 +28,7 @@ + #include "focus_cycle_indicator.h" + #include "moveresize.h" + #include "screen.h" ++#include "edges.h" + #include "obrender/theme.h" + #include "obt/display.h" + #include "obt/xqueue.h" +@@ -1386,6 +1387,22 @@ + return OB_FRAME_CONTEXT_MOVE_RESIZE; + else if (!g_ascii_strcasecmp("Dock", name)) + return OB_FRAME_CONTEXT_DOCK; ++ else if (!g_ascii_strcasecmp("ScreenTop", name)) ++ return OB_FRAME_CONTEXT_EDGE_TOP; ++ else if (!g_ascii_strcasecmp("ScreenTopRight", name)) ++ return OB_FRAME_CONTEXT_EDGE_TOPRIGHT; ++ else if (!g_ascii_strcasecmp("ScreenRight", name)) ++ return OB_FRAME_CONTEXT_EDGE_RIGHT; ++ else if (!g_ascii_strcasecmp("ScreenBottomRight", name)) ++ return OB_FRAME_CONTEXT_EDGE_BOTTOMRIGHT; ++ else if (!g_ascii_strcasecmp("ScreenBottom", name)) ++ return OB_FRAME_CONTEXT_EDGE_BOTTOM; ++ else if (!g_ascii_strcasecmp("ScreenBottomLeft", name)) ++ return OB_FRAME_CONTEXT_EDGE_BOTTOMLEFT; ++ else if (!g_ascii_strcasecmp("ScreenLeft", name)) ++ return OB_FRAME_CONTEXT_EDGE_LEFT; ++ else if (!g_ascii_strcasecmp("ScreenTopLeft", name)) ++ return OB_FRAME_CONTEXT_EDGE_TOPLEFT; + + return OB_FRAME_CONTEXT_NONE; + } +@@ -1397,12 +1414,14 @@ + + if (moveresize_in_progress) + return OB_FRAME_CONTEXT_MOVE_RESIZE; +- + if (win == obt_root(ob_screen)) + return OB_FRAME_CONTEXT_ROOT; + if ((obwin = window_find(win))) { + if (WINDOW_IS_DOCK(obwin)) { + return OB_FRAME_CONTEXT_DOCK; ++ } else if (WINDOW_IS_EDGE(obwin)) { ++ ObEdge *edge = (ObEdge *)obwin; ++ return OB_FRAME_CONTEXT_EDGE_TOP + edge->location; + } + } + if (client == NULL) return OB_FRAME_CONTEXT_NONE; +diff -urN /mnt/i/linux/openbox/openbox/openbox/frame.h ./openbox/frame.h +--- /mnt/i/linux/openbox/openbox/openbox/frame.h 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/frame.h 2015-01-12 21:04:16.303754384 +0200 +@@ -54,6 +54,14 @@ + a move/resize */ + OB_FRAME_CONTEXT_MOVE_RESIZE, + OB_FRAME_CONTEXT_DOCK, ++ OB_FRAME_CONTEXT_EDGE_TOP, ++ OB_FRAME_CONTEXT_EDGE_TOPRIGHT, ++ OB_FRAME_CONTEXT_EDGE_RIGHT, ++ OB_FRAME_CONTEXT_EDGE_BOTTOMRIGHT, ++ OB_FRAME_CONTEXT_EDGE_BOTTOM, ++ OB_FRAME_CONTEXT_EDGE_BOTTOMLEFT, ++ OB_FRAME_CONTEXT_EDGE_LEFT, ++ OB_FRAME_CONTEXT_EDGE_TOPLEFT, + OB_FRAME_NUM_CONTEXTS + } ObFrameContext; + +diff -urN /mnt/i/linux/openbox/openbox/openbox/openbox.c ./openbox/openbox.c +--- /mnt/i/linux/openbox/openbox/openbox/openbox.c 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/openbox.c 2015-01-12 21:04:16.303754384 +0200 +@@ -21,6 +21,7 @@ + #include "openbox.h" + #include "session.h" + #include "dock.h" ++#include "edges.h" + #include "event.h" + #include "menu.h" + #include "client.h" +@@ -327,6 +328,7 @@ + mouse_startup(reconfigure); + menu_frame_startup(reconfigure); + menu_startup(reconfigure); ++ edges_startup(reconfigure); + prompt_startup(reconfigure); + + /* do this after everything is started so no events will get +@@ -392,6 +394,7 @@ + window_unmanage_all(); + + prompt_shutdown(reconfigure); ++ edges_shutdown(reconfigure); + menu_shutdown(reconfigure); + menu_frame_shutdown(reconfigure); + mouse_shutdown(reconfigure); +diff -urN /mnt/i/linux/openbox/openbox/openbox/screen.c ./openbox/screen.c +--- /mnt/i/linux/openbox/openbox/openbox/screen.c 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/screen.c 2015-01-12 21:04:26.665753953 +0200 +@@ -20,6 +20,7 @@ + #include "debug.h" + #include "openbox.h" + #include "dock.h" ++#include "edges.h" + #include "grab.h" + #include "startupnotify.h" + #include "moveresize.h" +@@ -500,6 +501,7 @@ + + /* this calls screen_update_areas(), which we need ! */ + dock_configure(); ++ edges_configure(); + + for (it = client_list; it; it = g_list_next(it)) { + client_move_onscreen(it->data, FALSE); +diff -urN /mnt/i/linux/openbox/openbox/openbox/window.c ./openbox/window.c +--- /mnt/i/linux/openbox/openbox/openbox/window.c 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/window.c 2015-01-12 21:04:21.164754182 +0200 +@@ -24,6 +24,7 @@ + #include "frame.h" + #include "openbox.h" + #include "prompt.h" ++#include "edges.h" + #include "debug.h" + #include "grab.h" + #include "obt/prop.h" +@@ -62,6 +63,8 @@ + return WINDOW_AS_INTERNAL(self)->window; + case OB_WINDOW_CLASS_PROMPT: + return WINDOW_AS_PROMPT(self)->super.window; ++ case OB_WINDOW_CLASS_EDGE: ++ return WINDOW_AS_EDGE(self)->win; + } + g_assert_not_reached(); + return None; +@@ -74,6 +77,7 @@ + return config_dock_layer; + case OB_WINDOW_CLASS_CLIENT: + return ((ObClient*)self)->layer; ++ case OB_WINDOW_CLASS_EDGE: + case OB_WINDOW_CLASS_MENUFRAME: + case OB_WINDOW_CLASS_INTERNAL: + return OB_STACKING_LAYER_INTERNAL; +diff -urN /mnt/i/linux/openbox/openbox/openbox/window.h ./openbox/window.h +--- /mnt/i/linux/openbox/openbox/openbox/window.h 2014-11-07 19:58:40.000000000 +0200 ++++ ./openbox/window.h 2015-01-12 21:04:16.303754384 +0200 +@@ -32,7 +32,8 @@ + OB_WINDOW_CLASS_DOCK, + OB_WINDOW_CLASS_CLIENT, + OB_WINDOW_CLASS_INTERNAL, +- OB_WINDOW_CLASS_PROMPT ++ OB_WINDOW_CLASS_PROMPT, ++ OB_WINDOW_CLASS_EDGE + } ObWindowClass; + + /* In order to be an ObWindow, you need to make this struct the top of your +@@ -51,6 +52,8 @@ + (((ObWindow*)win)->type == OB_WINDOW_CLASS_INTERNAL) + #define WINDOW_IS_PROMPT(win) \ + (((ObWindow*)win)->type == OB_WINDOW_CLASS_PROMPT) ++#define WINDOW_IS_EDGE(win) \ ++ (((ObWindow*)win)->type == OB_WINDOW_CLASS_EDGE) + + struct _ObMenu; + struct _ObDock; +@@ -63,12 +66,14 @@ + #define WINDOW_AS_CLIENT(win) ((struct _ObClient*)win) + #define WINDOW_AS_INTERNAL(win) ((struct _ObInternalWindow*)win) + #define WINDOW_AS_PROMPT(win) ((struct _ObPrompt*)win) ++#define WINDOW_AS_EDGE(win) ((struct _ObEdge*)win) + + #define MENUFRAME_AS_WINDOW(menu) ((ObWindow*)menu) + #define DOCK_AS_WINDOW(dock) ((ObWindow*)dock) + #define CLIENT_AS_WINDOW(client) ((ObWindow*)client) + #define INTERNAL_AS_WINDOW(intern) ((ObWindow*)intern) + #define PROMPT_AS_WINDOW(prompt) ((ObWindow*)prompt) ++#define EDGE_AS_WINDOW(edge) ((ObWindow*)edge) + + void window_startup (gboolean reconfig); + void window_shutdown(gboolean reconfig); diff --git a/import-bind.patch b/import-bind.patch new file mode 100644 index 000000000000..89498bce3605 --- /dev/null +++ b/import-bind.patch @@ -0,0 +1,107 @@ +commit ce42ade7286fa387ec77d66d79b546ddeae1592b +Author: Alexey Korop <avkorop@i.ua> +Date: Sun Mar 15 19:03:24 2015 +0200 + + import-bind.patch + +diff --git a/openbox/config.c b/openbox/config.c +index 7a4eaa1..8d50846 100644 +--- a/openbox/config.c ++++ b/openbox/config.c +@@ -572,6 +572,18 @@ static void parse_mouse(xmlNodePtr node, gpointer d) + continue; + } + ++ xmlNodePtr import_node = obt_xml_find_node(n->children, "import"); ++ while (import_node) { // import bindings from another context ++ gchar *s = obt_xml_node_string(import_node); ++ if (s) { ++ ObFrameContext import_ctx = frame_context_from_string(s); ++ if (import_ctx != OB_FRAME_CONTEXT_NONE) { ++ mouse_import_bind(cx, import_ctx); ++ } ++ } ++ import_node = obt_xml_find_node(import_node->next, "import"); ++ } ++ + for (nbut = obt_xml_find_node(n->children, "mousebind"); + nbut; + nbut = obt_xml_find_node(nbut->next, "mousebind")) +diff --git a/openbox/mouse.c b/openbox/mouse.c +index 4da22f3..08a06d4 100644 +--- a/openbox/mouse.c ++++ b/openbox/mouse.c +@@ -369,20 +369,14 @@ gboolean mouse_event(ObClient *client, XEvent *e) + return used; + } + +-gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context, ++static gboolean mouse_bind_b(guint state, guint button, ObFrameContext context, + ObMouseAction mact, ObActionsAct *action) + { +- guint state = 0, button = 0; + ObMouseBinding *b; + GSList *it; + + g_assert(context != OB_FRAME_CONTEXT_NONE); + +- if (!translate_button(buttonstr, &state, &button)) { +- g_message(_("Invalid button \"%s\" in mouse binding"), buttonstr); +- return FALSE; +- } +- + for (it = bound_contexts[context]; it; it = g_slist_next(it)) { + b = it->data; + if (b->state == state && b->button == button) { +@@ -401,6 +395,39 @@ gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context, + return TRUE; + } + ++gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context, ++ ObMouseAction mact, ObActionsAct *action) ++{ ++ guint state = 0, button = 0; ++ ObMouseBinding *b; ++ GSList *it; ++ ++ if (!translate_button(buttonstr, &state, &button)) { ++ g_message(_("Invalid button \"%s\" in mouse binding"), buttonstr); ++ return FALSE; ++ } ++ return(mouse_bind_b(state, button, context, mact, action)); ++} ++ ++void mouse_import_bind(ObFrameContext context, ObFrameContext import_ctx) ++{ ++ GSList *it; ++ ObActionsAct *action; ++ GSList *jt; ++ ++ for (it = bound_contexts[import_ctx]; it; it = g_slist_next(it)) { ++ ObMouseBinding *b = it->data; ++ gint j; ++ for (j = 0; j < OB_NUM_MOUSE_ACTIONS; ++j) { ++ for (jt = b->actions[j]; jt; jt = g_slist_next(jt)) { ++ action = jt->data; ++ actions_act_ref(action); ++ mouse_bind_b(b->state, b->button, context, j, action); ++ } ++ } ++ } ++} ++ + void mouse_startup(gboolean reconfig) + { + grab_all_clients(TRUE); +diff --git a/openbox/mouse.h b/openbox/mouse.h +index de4c0ec..90749b4 100644 +--- a/openbox/mouse.h ++++ b/openbox/mouse.h +@@ -32,6 +32,7 @@ void mouse_shutdown(gboolean reconfig); + gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context, + ObMouseAction mact, struct _ObActionsAct *action); + void mouse_unbind_all(void); ++void mouse_import_bind(ObFrameContext context, ObFrameContext import_ctx); + + gboolean mouse_event(struct _ObClient *client, XEvent *e); + diff --git a/install b/install new file mode 100755 index 000000000000..4955fa6af71b --- /dev/null +++ b/install @@ -0,0 +1,14 @@ +post_install() { + echo "Config samples see in /etc/openbox_eui/samples." + echo "If You use obconf and/or lxappearance-obconf You must" + echo " rebuild these packages from sources (yaourt -Sb obconf)" +} + +post_upgrade() { + post_install +} + +post_remove() { + echo "If You use obconf and/or lxappearance-obconf You must" + echo "reinstall these packages from official repository" +} diff --git a/keybind_item.patch b/keybind_item.patch new file mode 100644 index 000000000000..64f212e7e115 --- /dev/null +++ b/keybind_item.patch @@ -0,0 +1,44 @@ +diff -ruw -X openbox-efc7efc/.gitignore openbox-efc7efc/openbox/menu.c openbox-efc7efc^/openbox/menu.c +--- openbox-efc7efc/openbox/menu.c 2014-12-06 19:20:47.000000000 +0200 ++++ openbox-efc7efc^/openbox/menu.c 2014-12-06 18:46:06.000000000 +0200 +@@ -116,6 +116,7 @@ + } + + g_assert(menu_parse_state.parent == NULL); ++ keyboard_rebind(); + } + + void menu_shutdown(gboolean reconfig) +@@ -282,6 +283,8 @@ + gboolean is_default = FALSE; + gchar *icon; + ObMenuEntry *e; ++ GList *keylist; ++ gchar *keystring, **keys, **key; + + if (state->parent) { + /* Don't try to extract "icon" attribute if icons in user-defined +@@ -292,11 +295,22 @@ + xmlNodePtr c; + GSList *acts = NULL; + ++ keylist = NULL; ++ if (obt_xml_attr_string(node, "key", &keystring)) { ++ keys = g_strsplit(keystring, " ", 0); ++ for (key = keys; *key; ++key) ++ keylist = g_list_append(keylist, *key); ++ } + c = obt_xml_find_node(node->children, "action"); + while (c) { + ObActionsAct *action = actions_parse(c); +- if (action) ++ if (action) { ++ if (keylist) { ++ actions_act_ref(action); ++ keyboard_bind(keylist, action); ++ } + acts = g_slist_append(acts, action); ++ } + c = obt_xml_find_node(c->next, "action"); + } + e = menu_add_normal(state->parent, -1, label, acts, TRUE); diff --git a/keybind_menu2.patch b/keybind_menu2.patch new file mode 100644 index 000000000000..93fae5e86ce4 --- /dev/null +++ b/keybind_menu2.patch @@ -0,0 +1,161 @@ +commit d112fc0e8a9d9d5fdd07a9a3698b76d1cfc6eb5c +Author: Alexey Korop <avkorop@i.ua> +Date: Sun Mar 15 17:28:50 2015 +0200 + + keybind_menu.patch + +diff --git a/openbox/actions.c b/openbox/actions.c +index bf00c6c..994740a 100644 +--- a/openbox/actions.c ++++ b/openbox/actions.c +@@ -28,6 +28,7 @@ + #include "debug.h" + + #include "actions/all.h" ++#include "actions/showmenu.h" + + static void actions_definition_ref(ObActionsDefinition *def); + static void actions_definition_unref(ObActionsDefinition *def); +@@ -237,6 +238,16 @@ static ObActionsAct* actions_build_act_from_string(const gchar *name) + return act; + } + ++ObActionsAct* actions_build_act_ShowMenu(const gchar *name) ++{ ++ ObActionsAct *act; ++ ++ act = actions_parse_string(ACTION_SHOW_MENU); ++ act->options = default_show_menu_options(g_strdup(name)); ++ return act; ++} ++ ++ + ObActionsAct* actions_parse_string(const gchar *name) + { + ObActionsAct *act = NULL; +diff --git a/openbox/actions.h b/openbox/actions.h +index f8e1ba8..9d25b33 100644 +--- a/openbox/actions.h ++++ b/openbox/actions.h +@@ -15,6 +15,8 @@ + + See the COPYING file for a copy of the GNU General Public License. + */ ++#ifndef __actions_h ++#define __actions_h + + #include "misc.h" + #include "frame.h" +@@ -121,3 +123,8 @@ gboolean actions_interactive_input_event(XEvent *e); + + /*! Function for actions to call when they are moving a client around */ + void actions_client_move(ObActionsData *data, gboolean start); ++ ++#define ACTION_SHOW_MENU "ShowMenu" ++ObActionsAct* actions_build_act_ShowMenu(const gchar *name); ++ ++#endif +diff --git a/openbox/actions/showmenu.c b/openbox/actions/showmenu.c +index 7411e98..49047f0 100644 +--- a/openbox/actions/showmenu.c ++++ b/openbox/actions/showmenu.c +@@ -5,6 +5,7 @@ + #include "openbox/screen.h" + #include "openbox/config.h" + #include <glib.h> ++#include "showmenu.h" + + typedef struct { + gchar *name; +@@ -18,9 +19,20 @@ static gpointer setup_func(xmlNodePtr node); + static void free_func(gpointer options); + static gboolean run_func(ObActionsData *data, gpointer options); + ++gpointer default_show_menu_options(gchar* name) ++{ ++ Options *o; ++ ++ o = g_slice_new0(Options); ++ o->monitor = -1; ++ o->name = name; ++ return o; ++} ++ ++ + void action_showmenu_startup(void) + { +- actions_register("ShowMenu", setup_func, free_func, run_func); ++ actions_register(ACTION_SHOW_MENU, setup_func, free_func, run_func); + } + + static gpointer setup_func(xmlNodePtr node) +@@ -29,11 +41,8 @@ static gpointer setup_func(xmlNodePtr node) + Options *o; + gboolean x_pos_given = FALSE; + +- o = g_slice_new0(Options); +- o->monitor = -1; +- +- if ((n = obt_xml_find_node(node, "menu"))) +- o->name = obt_xml_node_string(n); ++ n = obt_xml_find_node(node, "menu"); ++ o = (Options*)default_show_menu_options(obt_xml_node_string(n)); + + if ((n = obt_xml_find_node(node, "position"))) { + if ((c = obt_xml_find_node(n->children, "x"))) { +diff --git a/openbox/actions/showmenu.h b/openbox/actions/showmenu.h +new file mode 100644 +index 0000000..217dc90 +--- /dev/null ++++ b/openbox/actions/showmenu.h +@@ -0,0 +1,2 @@ ++/* in fact, return Options* */ ++gpointer default_show_menu_options(gchar* name); +diff --git a/openbox/menu.c b/openbox/menu.c +index 057e54a..4d461f1 100644 +--- a/openbox/menu.c ++++ b/openbox/menu.c +@@ -19,6 +19,7 @@ + + #include "debug.h" + #include "menu.h" ++#include "actions.h" + #include "openbox.h" + #include "stacking.h" + #include "grab.h" +@@ -353,14 +354,23 @@ static void parse_menu(xmlNodePtr node, gpointer data) + ObMenu *menu; + ObMenuEntry *e; + gchar *icon; ++ GList *keylist = NULL; ++ gchar *keystring, **keys, **key; + + if (!obt_xml_attr_string(node, "id", &name)) + goto parse_menu_fail; + ++ if (obt_xml_attr_string(node, "key", &keystring)) { // global keybind ++ keys = g_strsplit(keystring, " ", 0); ++ for (key = keys; *key; ++key) ++ keylist = g_list_append(keylist, *key); ++ } ++ + if (!g_hash_table_lookup(menu_hash, name)) { + if (!obt_xml_attr_string_unstripped(node, "label", &title)) + goto parse_menu_fail; + ++ + if ((menu = menu_new(name, title, TRUE, NULL))) { + menu->pipe_creator = state->pipe_creator; + if (obt_xml_attr_string(node, "execute", &script)) { +@@ -373,6 +383,11 @@ static void parse_menu(xmlNodePtr node, gpointer data) + obt_xml_tree(menu_parse_inst, node->children); + state->parent = old; + } ++ if (keylist) { // add keybind to show this menu ++ ObActionsAct *action; ++ action = actions_build_act_ShowMenu(name); ++ keyboard_bind(keylist, action); ++ } + } + } + diff --git a/menu.xml b/menu.xml new file mode 100644 index 000000000000..e32bae74fe2c --- /dev/null +++ b/menu.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<openbox_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd"> + <!-- main menu; hotkey - Win+Space --> + <menu id="root-menu" label="Openbox 3" key="W-space"> + <menu id="desktop-app-menu" icon="/usr/share/icons/gnome/16x16/categories/applications-other.png" label="Applications" execute="xdg_menu --format openbox3-pipe" key=""/> + <!-- Run dialog; hotkey - Win+r --> + <item icon="/usr/share/icons/gnome/16x16/actions/system-run.png" label="Run Program" key="W-r"> + <action name="Execute"> + <command>gmrun</command> + </action> + </item> + <!-- "Exit" menu with external scripts; default item - shutdown. + For shutdown You may press "Win+Space" (main menu), then "x" (e_Xit menu) --> + <menu id="exit" label="e_Xit" icon="/usr/share/icons/gnome/16x16/actions/system-log-out.png" key="W-x"> + <item icon="/usr/share/icons/gnome/16x16/actions/media-playback-pause.png" label="hibernate"> + <action name="Execute"> + <execute>.hibernate</execute> + </action> + </item> + <item icon="/usr/share/icons/gnome/16x16/actions/system-log-out.png" label="Logout"> + <action name="Execute"> + <execute>.logoff</execute> + </action> + </item> + <item icon="/usr/share/icons/gnome/16x16/actions/window-close.png" label="Reboot"> + <action name="Execute"> + <execute>.reboot</execute> + </action> + </item> + <item icon="/usr/share/icons/gnome/16x16/actions/system-shutdown.png" label="Shutdown" default="yes"> + <action name="Execute"> + <execute>.shutdown</execute> + </action> + </item> + </menu> + </menu> +</openbox_menu> diff --git a/menu_w_def9.patch b/menu_w_def9.patch new file mode 100644 index 000000000000..dd2f59dfdab2 --- /dev/null +++ b/menu_w_def9.patch @@ -0,0 +1,754 @@ +commit 36f80459b6b8f947023ed551dd61cdd3d8d16d0d +Author: Alexey Korop <avkorop@i.ua> +Date: Sat Mar 14 21:07:58 2015 +0200 + + menu_w_def8.patch + +diff --git a/obrender/theme.c b/obrender/theme.c +index 2a4f6e1..7b1969f 100644 +--- a/obrender/theme.c ++++ b/obrender/theme.c +@@ -215,6 +215,8 @@ RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name, + theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1); + theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1); + theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1); ++ theme->a_menu_bullet_def_normal = RrAppearanceNew(inst, 1); ++ theme->a_menu_bullet_def_selected = RrAppearanceNew(inst, 1); + theme->a_clear = RrAppearanceNew(inst, 0); + theme->a_clear_tex = RrAppearanceNew(inst, 1); + theme->osd_bg = RrAppearanceNew(inst, 0); +@@ -527,6 +529,13 @@ RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name, + theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data); + } + ++ /* submenu with default bullet mask */ ++ if (!read_mask(inst, path, "bullet_def.xbm", &theme->menu_bullet_def_mask)) ++ { ++ guchar data[] = { 0xFF, 0x85, 0x8D, 0x9D, 0xBD, 0x9D, 0x8D, 0x85, 0xFF }; ++ theme->menu_bullet_def_mask = RrPixmapMaskNew(inst, 8, 9, (gchar*)data); ++ } ++ + /* up and down arrows */ + { + guchar data[] = { 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00 }; +@@ -618,6 +627,8 @@ RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name, + theme->a_menu_text_disabled_selected->surface.grad = + theme->a_menu_bullet_normal->surface.grad = + theme->a_menu_bullet_selected->surface.grad = RR_SURFACE_PARENTREL; ++ theme->a_menu_bullet_def_normal->surface.grad = ++ theme->a_menu_bullet_def_selected->surface.grad = RR_SURFACE_PARENTREL; + + /* set up the textures */ + theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT; +@@ -932,13 +943,26 @@ RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name, + + theme->a_menu_bullet_normal->texture[0].type = + theme->a_menu_bullet_selected->texture[0].type = RR_TEXTURE_MASK; ++ theme->a_menu_bullet_def_normal->texture[0].type = ++ theme->a_menu_bullet_def_selected->texture[0].type = RR_TEXTURE_MASK; + theme->a_menu_bullet_normal->texture[0].data.mask.mask = + theme->a_menu_bullet_selected->texture[0].data.mask.mask = + theme->menu_bullet_mask; ++ theme->a_menu_bullet_def_normal->texture[0].data.mask.mask = ++ theme->a_menu_bullet_def_selected->texture[0].data.mask.mask = ++ theme->menu_bullet_def_mask; + theme->a_menu_bullet_normal->texture[0].data.mask.color = + theme->menu_bullet_color; + theme->a_menu_bullet_selected->texture[0].data.mask.color = + theme->menu_bullet_selected_color; ++ theme->a_menu_bullet_def_normal->texture[0].data.mask.color = ++ theme->menu_bullet_color; ++ theme->a_menu_bullet_def_selected->texture[0].data.mask.color = ++ theme->menu_bullet_selected_color; ++ theme->a_menu_bullet_def_normal->texture[0].data.mask.color = ++ theme->menu_bullet_color; ++ theme->a_menu_bullet_def_selected->texture[0].data.mask.color = ++ theme->menu_bullet_selected_color; + + g_free(path); + XrmDestroyDatabase(db); +@@ -1065,6 +1089,7 @@ void RrThemeFree(RrTheme *theme) + g_free(theme->def_win_icon); + + RrPixmapMaskFree(theme->menu_bullet_mask); ++ RrPixmapMaskFree(theme->menu_bullet_def_mask); + RrPixmapMaskFree(theme->down_arrow_mask); + RrPixmapMaskFree(theme->up_arrow_mask); + +@@ -1097,6 +1122,8 @@ void RrThemeFree(RrTheme *theme) + RrAppearanceFree(theme->a_menu_text_disabled_selected); + RrAppearanceFree(theme->a_menu_bullet_normal); + RrAppearanceFree(theme->a_menu_bullet_selected); ++ RrAppearanceFree(theme->a_menu_bullet_def_normal); ++ RrAppearanceFree(theme->a_menu_bullet_def_selected); + RrAppearanceFree(theme->a_clear); + RrAppearanceFree(theme->a_clear_tex); + RrAppearanceFree(theme->osd_bg); +diff --git a/obrender/theme.h b/obrender/theme.h +index 8797f0b..2c732fc 100644 +--- a/obrender/theme.h ++++ b/obrender/theme.h +@@ -123,6 +123,7 @@ struct _RrTheme { + + /* style settings - masks */ + RrPixmapMask *menu_bullet_mask; /* submenu pointer */ ++ RrPixmapMask *menu_bullet_def_mask; /* submenu with default pointer */ + #if 0 + RrPixmapMask *menu_toggle_mask; /* menu boolean */ + #endif +@@ -161,6 +162,8 @@ struct _RrTheme { + RrAppearance *a_menu_text_selected; + RrAppearance *a_menu_bullet_normal; + RrAppearance *a_menu_bullet_selected; ++ RrAppearance *a_menu_bullet_def_normal; ++ RrAppearance *a_menu_bullet_def_selected; + RrAppearance *a_clear; /* clear with no texture */ + RrAppearance *a_clear_tex; /* clear with a texture */ + +diff --git a/openbox/client_list_combined_menu.c b/openbox/client_list_combined_menu.c +index c26b6fa..84eb506 100644 +--- a/openbox/client_list_combined_menu.c ++++ b/openbox/client_list_combined_menu.c +@@ -74,9 +74,9 @@ static gboolean self_update(ObMenuFrame *frame, gpointer data) + } + + if (config_menu_show_icons) { +- e->data.normal.icon = client_icon(c); +- RrImageRef(e->data.normal.icon); +- e->data.normal.icon_alpha = ++ e->icon = client_icon(c); ++ RrImageRef(e->icon); ++ e->icon_alpha = + c->iconic ? OB_ICONIC_ALPHA : 0xff; + } + +diff --git a/openbox/client_list_menu.c b/openbox/client_list_menu.c +index f3df2a5..4f85935 100644 +--- a/openbox/client_list_menu.c ++++ b/openbox/client_list_menu.c +@@ -70,9 +70,9 @@ static gboolean desk_menu_update(ObMenuFrame *frame, gpointer data) + } + + if (config_menu_show_icons) { +- e->data.normal.icon = client_icon(c); +- RrImageRef(e->data.normal.icon); +- e->data.normal.icon_alpha = c->iconic ? OB_ICONIC_ALPHA : 0xff; ++ e->icon = client_icon(c); ++ RrImageRef(e->icon); ++ e->icon_alpha = c->iconic ? OB_ICONIC_ALPHA : 0xff; + } + + e->data.normal.data = c; +diff --git a/openbox/client_menu.c b/openbox/client_menu.c +index 4a3b286..6d5c4c7 100644 +--- a/openbox/client_menu.c ++++ b/openbox/client_menu.c +@@ -57,10 +57,10 @@ enum { + + static void set_icon_color(ObMenuEntry *e) + { +- e->data.normal.mask_normal_color = ob_rr_theme->menu_color; +- e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color; +- e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color; +- e->data.normal.mask_disabled_selected_color = ++ e->mask_normal_color = ob_rr_theme->menu_color; ++ e->mask_selected_color = ob_rr_theme->menu_selected_color; ++ e->mask_disabled_color = ob_rr_theme->menu_disabled_color; ++ e->mask_disabled_selected_color = + ob_rr_theme->menu_disabled_selected_color; + } + +@@ -276,10 +276,10 @@ static gboolean send_to_menu_update(ObMenuFrame *frame, gpointer data) + if ((desk == DESKTOP_ALL && c->desktop != DESKTOP_ALL) || + (c->desktop == DESKTOP_ALL && desk == screen_desktop)) + { +- e->data.normal.mask = ob_rr_theme->btn_desk->unpressed_mask; ++ e->mask = ob_rr_theme->btn_desk->unpressed_mask; + set_icon_color(e); + } else +- e->data.normal.mask = NULL; ++ e->mask = NULL; + } + + return TRUE; /* show the menu */ +@@ -392,7 +392,7 @@ void client_menu_startup(void) + menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME); + + e = menu_add_normal(menu, CLIENT_RESTORE, _("R_estore"), NULL, TRUE); +- e->data.normal.mask = ob_rr_theme->btn_max->unpressed_toggled_mask; ++ e->mask = ob_rr_theme->btn_max->unpressed_toggled_mask; + set_icon_color(e); + + menu_add_normal(menu, CLIENT_MOVE, _("_Move"), NULL, TRUE); +@@ -400,15 +400,15 @@ void client_menu_startup(void) + menu_add_normal(menu, CLIENT_RESIZE, _("Resi_ze"), NULL, TRUE); + + e = menu_add_normal(menu, CLIENT_ICONIFY, _("Ico_nify"), NULL, TRUE); +- e->data.normal.mask = ob_rr_theme->btn_iconify->unpressed_mask; ++ e->mask = ob_rr_theme->btn_iconify->unpressed_mask; + set_icon_color(e); + + e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Ma_ximize"), NULL, TRUE); +- e->data.normal.mask = ob_rr_theme->btn_max->unpressed_mask; ++ e->mask = ob_rr_theme->btn_max->unpressed_mask; + set_icon_color(e); + + e = menu_add_normal(menu, CLIENT_SHADE, _("_Roll up/down"), NULL, TRUE); +- e->data.normal.mask = ob_rr_theme->btn_shade->unpressed_mask; ++ e->mask = ob_rr_theme->btn_shade->unpressed_mask; + set_icon_color(e); + + menu_add_normal(menu, CLIENT_DECORATE, _("Un/_Decorate"), NULL, TRUE); +@@ -416,6 +416,6 @@ void client_menu_startup(void) + menu_add_separator(menu, -1, NULL); + + e = menu_add_normal(menu, CLIENT_CLOSE, _("_Close"), NULL, TRUE); +- e->data.normal.mask = ob_rr_theme->btn_close->unpressed_mask; ++ e->mask = ob_rr_theme->btn_close->unpressed_mask; + set_icon_color(e); + } +diff --git a/openbox/event.c b/openbox/event.c +index 5774f67..fd3ecb5 100644 +--- a/openbox/event.c ++++ b/openbox/event.c +@@ -1845,9 +1845,17 @@ static gboolean event_handle_menu_input(XEvent *ev) + menu_frame_select(e->frame->child, NULL, TRUE); + } + menu_frame_select(e->frame, e, TRUE); +- if (ev->type == ButtonRelease) ++ if ((ev->type == ButtonRelease) && (ev->xbutton.button==1) ++ && (menu_entry_frame_x_not_in_bullet(e->frame, ev->xbutton.x))) ++ { ++ /* execute clicked entry or it's default entry */ ++ if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { ++ if (e->frame->child && e->frame->child->default_entry) ++ e = e->frame->child->default_entry; ++ } + menu_entry_frame_execute(e, ev->xbutton.state); + } ++ } + else + menu_frame_hide_all(); + } +@@ -1892,24 +1900,15 @@ static gboolean event_handle_menu_input(XEvent *ev) + ret = TRUE; + } + +- else if (sym == XK_Right || sym == XK_Return || sym == XK_KP_Enter) ++ else if (sym == XK_Right) { ++ /* Right goes to the selected submenu */ ++ if (frame->selected && ++ frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) + { +- /* Right and enter goes to the selected submenu. +- Enter executes instead if it's not on a submenu. */ +- +- if (frame->selected) { +- const ObMenuEntryType t = frame->selected->entry->type; +- +- if (t == OB_MENU_ENTRY_TYPE_SUBMENU) { + /* make sure it is visible */ + menu_frame_select(frame, frame->selected, TRUE); +- /* move focus to the child menu */ + menu_frame_select_next(frame->child); + } +- else if (sym != XK_Right) { +- frame->press_doexec = TRUE; +- } +- } + ret = TRUE; + } + +@@ -1933,6 +1932,14 @@ static gboolean event_handle_menu_input(XEvent *ev) + ret = TRUE; + } + ++ else if (sym == XK_Return || sym == XK_KP_Enter) { ++ if (frame->selected && ++ frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) ++ menu_frame_select(frame, frame->selected, TRUE); ++ frame->press_doexec = TRUE; ++ ret = TRUE; ++ } ++ + /* keyboard accelerator shortcuts. (if it was a valid key) */ + else if (frame->entries && + (unikey = +@@ -1979,13 +1986,14 @@ static gboolean event_handle_menu_input(XEvent *ev) + menu_frame_select(frame, found, TRUE); + + if (num_found == 1) { +- if (found->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { ++ if (found->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU && ++ ! frame->child->default_entry) ++ { + /* move focus to the child menu */ + menu_frame_select_next(frame->child); + } +- else { ++ else + frame->press_doexec = TRUE; +- } + } + ret = TRUE; + } +@@ -1995,14 +2003,22 @@ static gboolean event_handle_menu_input(XEvent *ev) + /* Use KeyRelease events for running things so that the key release + doesn't get sent to the focused application. + +- Allow ControlMask only, and don't bother if the menu is empty */ +- else if (ev->type == KeyRelease && (mods & ~ControlMask) == 0) { +- if (frame->press_keycode == ev->xkey.keycode && ++ Allow all modifiers, and don't bother if the menu is empty */ ++ else if (ev->type == KeyRelease) { ++ if ((frame->press_keycode == ev->xkey.keycode) && + frame->got_press && + frame->press_doexec) + { +- if (frame->selected) +- menu_entry_frame_execute(frame->selected, ev->xkey.state); ++ if (frame->selected){ ++ ObMenuEntryFrame *e = frame->selected; ++ ++ /* execute selected entry or it's default entry */ ++ if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { ++ if (e->frame->child && e->frame->child->default_entry) ++ e = e->frame->child->default_entry; ++ } ++ menu_entry_frame_execute(e, ev->xkey.state); ++ } + } + } + } +diff --git a/openbox/menu.c b/openbox/menu.c +index 8804e12..6c0cf7e 100644 +--- a/openbox/menu.c ++++ b/openbox/menu.c +@@ -281,6 +281,7 @@ static void parse_menu_item(xmlNodePtr node, gpointer data) + { + ObMenuParseState *state = data; + gchar *label; ++ gboolean is_default = FALSE; + gchar *icon; + ObMenuEntry *e; + +@@ -288,6 +289,7 @@ static void parse_menu_item(xmlNodePtr node, gpointer data) + /* Don't try to extract "icon" attribute if icons in user-defined + menus are not enabled. */ + ++ obt_xml_attr_bool(node, "default", &is_default); + if (obt_xml_attr_string_unstripped(node, "label", &label)) { + xmlNodePtr c; + GSList *acts = NULL; +@@ -300,14 +302,15 @@ static void parse_menu_item(xmlNodePtr node, gpointer data) + c = obt_xml_find_node(c->next, "action"); + } + e = menu_add_normal(state->parent, -1, label, acts, TRUE); +- ++ if (is_default && !state->parent->default_entry) ++ state->parent->default_entry = e; + if (config_menu_show_icons && + obt_xml_attr_string(node, "icon", &icon)) + { +- e->data.normal.icon = RrImageNewFromName(ob_rr_icons, icon); ++ e->icon = RrImageNewFromName(ob_rr_icons, icon); + +- if (e->data.normal.icon) +- e->data.normal.icon_alpha = 0xff; ++ if (e->icon) ++ e->icon_alpha = 0xff; + + g_free(icon); + } +@@ -367,10 +370,10 @@ static void parse_menu(xmlNodePtr node, gpointer data) + if (config_menu_show_icons && + obt_xml_attr_string(node, "icon", &icon)) + { +- e->data.submenu.icon = RrImageNewFromName(ob_rr_icons, icon); ++ e->icon = RrImageNewFromName(ob_rr_icons, icon); + +- if (e->data.submenu.icon) +- e->data.submenu.icon_alpha = 0xff; ++ if (e->icon) ++ e->icon_alpha = 0xff; + + g_free(icon); + } +@@ -559,7 +562,7 @@ void menu_entry_unref(ObMenuEntry *self) + if (self && --self->ref == 0) { + switch (self->type) { + case OB_MENU_ENTRY_TYPE_NORMAL: +- RrImageUnref(self->data.normal.icon); ++ RrImageUnref(self->icon); + g_free(self->data.normal.label); + g_free(self->data.normal.collate_key); + while (self->data.normal.actions) { +@@ -570,7 +573,7 @@ void menu_entry_unref(ObMenuEntry *self) + } + break; + case OB_MENU_ENTRY_TYPE_SUBMENU: +- RrImageUnref(self->data.submenu.icon); ++ RrImageUnref(self->icon); + g_free(self->data.submenu.name); + break; + case OB_MENU_ENTRY_TYPE_SEPARATOR: +diff --git a/openbox/menu.h b/openbox/menu.h +index 8c2ecd7..04dcf10 100644 +--- a/openbox/menu.h ++++ b/openbox/menu.h +@@ -78,6 +78,9 @@ struct _ObMenu + /* ObMenuEntry list */ + GList *entries; + ++ /* default entry */ ++ ObMenuEntry *default_entry; ++ + /* plugin data */ + gpointer data; + +@@ -104,10 +107,6 @@ typedef enum + } ObMenuEntryType; + + struct _ObNormalMenuEntry { +- /* Icon stuff. If you set this, make sure you RrImageRef() it too. */ +- RrImage *icon; +- gint icon_alpha; +- + gchar *label; + gchar *collate_key; + /*! The shortcut key that would be used to activate this menu entry */ +@@ -123,21 +122,10 @@ struct _ObNormalMenuEntry { + /* List of ObActions */ + GSList *actions; + +- /* Mask icon */ +- RrPixmapMask *mask; +- RrColor *mask_normal_color; +- RrColor *mask_selected_color; +- RrColor *mask_disabled_color; +- RrColor *mask_disabled_selected_color; +- + gpointer data; + }; + + struct _ObSubmenuMenuEntry { +- /* Icon stuff. If you set this, make sure you RrImageRef() it too. */ +- RrImage *icon; +- gint icon_alpha; +- + gchar *name; + ObMenu *submenu; + +@@ -157,6 +145,17 @@ struct _ObMenuEntry + + gint id; + ++ /* Icon stuff. If you set this, make sure you RrImageRef() it too. */ ++ RrImage *icon; ++ gint icon_alpha; ++ ++ /* Mask icon */ ++ RrPixmapMask *mask; ++ RrColor *mask_normal_color; ++ RrColor *mask_selected_color; ++ RrColor *mask_disabled_color; ++ RrColor *mask_disabled_selected_color; ++ + union u { + ObNormalMenuEntry normal; + ObSubmenuMenuEntry submenu; +diff --git a/openbox/menuframe.c b/openbox/menuframe.c +index 2398031..943ff69 100644 +--- a/openbox/menuframe.c ++++ b/openbox/menuframe.c +@@ -35,6 +35,9 @@ + + #define ITEM_HEIGHT (ob_rr_theme->menu_font_height + 2*PADDING) + ++ /* offset at which the submenu bullet appears in the items */ ++#define BULLET_X (frame->text_x + frame->text_w - ITEM_HEIGHT + PADDING) ++ + #define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask |\ + LeaveWindowMask) + #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \ +@@ -187,7 +190,10 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, + self->icon = createWindow(self->window, 0, NULL); + g_hash_table_insert(menu_frame_map, &self->icon, self); + } +- if (entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { ++ if (entry->type == OB_MENU_ENTRY_TYPE_SUBMENU ++ || (entry->type == OB_MENU_ENTRY_TYPE_NORMAL ++ && entry == entry->menu->default_entry)) ++ { + self->bullet = createWindow(self->window, 0, NULL); + g_hash_table_insert(menu_frame_map, &self->bullet, self); + } +@@ -209,12 +215,11 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) + XDestroyWindow(obt_display, self->window); + g_hash_table_remove(menu_frame_map, &self->text); + g_hash_table_remove(menu_frame_map, &self->window); +- if ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) || +- (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) { ++ if (self->icon) { + XDestroyWindow(obt_display, self->icon); + g_hash_table_remove(menu_frame_map, &self->icon); + } +- if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { ++ if (self->bullet) { + XDestroyWindow(obt_display, self->bullet); + g_hash_table_remove(menu_frame_map, &self->bullet); + } +@@ -372,6 +377,7 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + gint th; /* temp */ + ObMenu *sub; + ObMenuFrame *frame = self->frame; ++ gboolean has_bullet; + + switch (self->entry->type) { + case OB_MENU_ENTRY_TYPE_NORMAL: +@@ -532,14 +538,34 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + g_assert_not_reached(); + } + +- if (((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) || +- (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) && +- self->entry->data.normal.icon) ++ has_bullet = FALSE; ++ if ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) && ++ frame->parent && ++ (self == self->frame->default_entry)) + { ++ // show the mark of the default item ++ RrAppearance *bullet_a; ++ ++ XMoveResizeWindow(obt_display, self->bullet, ++ PADDING, PADDING, ++ ITEM_HEIGHT - 2*PADDING, ++ ITEM_HEIGHT - 2*PADDING); ++ bullet_a = ((self == self->frame->selected) ? ++ ob_rr_theme->a_menu_bullet_def_selected : ++ ob_rr_theme->a_menu_bullet_def_normal); ++ bullet_a->surface.parent = item_a; ++ bullet_a->surface.parentx = 0; ++ bullet_a->surface.parenty = PADDING; ++ RrPaint(bullet_a, self->bullet, ++ self->frame->icon_x, ++ ITEM_HEIGHT - 2*PADDING); ++ has_bullet = TRUE; ++ } ++ if (self->entry->icon){ + RrAppearance *clear; + + XMoveResizeWindow(obt_display, self->icon, +- PADDING, frame->item_margin.top, ++ self->frame->icon_x, frame->item_margin.top, + ITEM_HEIGHT - frame->item_margin.top + - frame->item_margin.bottom, + ITEM_HEIGHT - frame->item_margin.top +@@ -549,9 +575,9 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + RrAppearanceClearTextures(clear); + clear->texture[0].type = RR_TEXTURE_IMAGE; + clear->texture[0].data.image.image = +- self->entry->data.normal.icon; ++ self->entry->icon; + clear->texture[0].data.image.alpha = +- self->entry->data.normal.icon_alpha; ++ self->entry->icon_alpha; + clear->surface.parent = item_a; + clear->surface.parentx = PADDING; + clear->surface.parenty = frame->item_margin.top; +@@ -562,13 +588,13 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + - frame->item_margin.bottom); + XMapWindow(obt_display, self->icon); + } else if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && +- self->entry->data.normal.mask) ++ self->entry->mask) + { + RrColor *c; + RrAppearance *clear; + + XMoveResizeWindow(obt_display, self->icon, +- PADDING, frame->item_margin.top, ++ self->frame->icon_x, frame->item_margin.top, + ITEM_HEIGHT - frame->item_margin.top + - frame->item_margin.bottom, + ITEM_HEIGHT - frame->item_margin.top +@@ -578,22 +604,22 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + RrAppearanceClearTextures(clear); + clear->texture[0].type = RR_TEXTURE_MASK; + clear->texture[0].data.mask.mask = +- self->entry->data.normal.mask; ++ self->entry->mask; + + c = (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && + !self->entry->data.normal.enabled ? + /* disabled */ + (self == self->frame->selected ? +- self->entry->data.normal.mask_disabled_selected_color : +- self->entry->data.normal.mask_disabled_color) : ++ self->entry->mask_disabled_selected_color : ++ self->entry->mask_disabled_color) : + /* enabled */ + (self == self->frame->selected ? +- self->entry->data.normal.mask_selected_color : +- self->entry->data.normal.mask_normal_color)); ++ self->entry->mask_selected_color : ++ self->entry->mask_normal_color)); + clear->texture[0].data.mask.color = c; + + clear->surface.parent = item_a; +- clear->surface.parentx = PADDING; ++ clear->surface.parentx = self->frame->icon_x; + clear->surface.parenty = frame->item_margin.top; + RrPaint(clear, self->icon, + ITEM_HEIGHT - frame->item_margin.top +@@ -607,13 +633,17 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { + RrAppearance *bullet_a; + XMoveResizeWindow(obt_display, self->bullet, +- self->frame->text_x + self->frame->text_w - +- ITEM_HEIGHT + PADDING, PADDING, ++ BULLET_X, PADDING, + ITEM_HEIGHT - 2*PADDING, + ITEM_HEIGHT - 2*PADDING); +- bullet_a = (self == self->frame->selected ? +- ob_rr_theme->a_menu_bullet_selected : +- ob_rr_theme->a_menu_bullet_normal); ++ if (sub->default_entry) ++ bullet_a = ((self == self->frame->selected) ? ++ ob_rr_theme->a_menu_bullet_def_selected : ++ ob_rr_theme->a_menu_bullet_def_normal); ++ else ++ bullet_a = ((self == self->frame->selected) ? ++ ob_rr_theme->a_menu_bullet_selected : ++ ob_rr_theme->a_menu_bullet_normal); + bullet_a->surface.parent = item_a; + bullet_a->surface.parentx = + self->frame->text_x + self->frame->text_w - ITEM_HEIGHT + PADDING; +@@ -621,8 +651,11 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) + RrPaint(bullet_a, self->bullet, + ITEM_HEIGHT - 2*PADDING, + ITEM_HEIGHT - 2*PADDING); ++ has_bullet = TRUE; ++ } ++ if (has_bullet) + XMapWindow(obt_display, self->bullet); +- } else ++ else + XUnmapWindow(obt_display, self->bullet); + + XFlush(obt_display); +@@ -767,8 +800,7 @@ void menu_frame_render(ObMenuFrame *self) + tw = MIN(tw, MAX_MENU_WIDTH); + th = ob_rr_theme->menu_font_height; + +- if (e->entry->data.normal.icon || +- e->entry->data.normal.mask) ++ if (e->entry->icon || e->entry->mask) + has_icon = TRUE; + break; + case OB_MENU_ENTRY_TYPE_SUBMENU: +@@ -778,8 +810,8 @@ void menu_frame_render(ObMenuFrame *self) + tw = MIN(tw, MAX_MENU_WIDTH); + th = ob_rr_theme->menu_font_height; + +- if (e->entry->data.normal.icon || +- e->entry->data.normal.mask) ++ if (e->entry->icon || ++ e->entry->mask) + has_icon = TRUE; + + tw += ITEM_HEIGHT - PADDING; +@@ -818,10 +850,17 @@ void menu_frame_render(ObMenuFrame *self) + h -= ob_rr_theme->mbwidth; + } + ++ self->icon_x = PADDING; + self->text_x = PADDING; + self->text_w = w; + + if (self->entries) { ++ gint def_w = ITEM_HEIGHT-2*PADDING; ++ if (self->parent && self->menu->default_entry) { ++ w += def_w; ++ self->icon_x += def_w; ++ self->text_x += def_w; ++ } + if (has_icon) { + w += ITEM_HEIGHT + PADDING; + self->text_x += ITEM_HEIGHT + PADDING; +@@ -852,6 +891,7 @@ static void menu_frame_update(ObMenuFrame *self) + { + GList *mit, *fit; + const Rect *a; ++ ObMenuEntry *menu_default_entry; + gint h; + + menu_pipe_execute(self->menu); +@@ -871,10 +911,13 @@ static void menu_frame_update(ObMenuFrame *self) + f->entry = mit->data; + } + ++ menu_default_entry = self->menu->default_entry; + /* if there are more menu entries than in the frame, add them */ + while (mit) { + ObMenuEntryFrame *e = menu_entry_frame_new(mit->data, self); + self->entries = g_list_append(self->entries, e); ++ if (menu_default_entry == e->entry) ++ self->default_entry = e; + mit = g_list_next(mit); + } + +@@ -957,7 +1000,7 @@ static gboolean menu_frame_is_visible(ObMenuFrame *self) + return !!(g_list_find(menu_frame_visible, self)); + } + +-static gboolean menu_frame_show(ObMenuFrame *self) ++gboolean menu_frame_show(ObMenuFrame *self) + { + GList *it; + +@@ -1178,6 +1221,11 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y) + return ret; + } + ++gboolean menu_entry_frame_x_not_in_bullet(ObMenuFrame* frame, gint x /* local */) ++{ ++ return(x <= BULLET_X); ++} ++ + static gboolean submenu_show_timeout(gpointer data) + { + g_assert(menu_frame_visible); +diff --git a/openbox/menuframe.h b/openbox/menuframe.h +index 7b295b6..ffcedf6 100644 +--- a/openbox/menuframe.h ++++ b/openbox/menuframe.h +@@ -55,6 +55,8 @@ struct _ObMenuFrame + + GList *entries; + ObMenuEntryFrame *selected; ++ /* default entry */ ++ ObMenuEntryFrame *default_entry; + + /* show entries from the menu starting at this index */ + guint show_from; +@@ -67,6 +69,7 @@ struct _ObMenuFrame + Strut item_margin; + gint inner_w; /* inside the borders */ + gint item_h; /* height of all normal items */ ++ gint icon_x; /* offset at which the icon or mask appears in the items */ + gint text_x; /* offset at which the text appears in the items */ + gint text_w; /* width of the text area in the items */ + gint text_h; /* height of the items */ +@@ -140,8 +143,10 @@ void menu_frame_select_last(ObMenuFrame *self); + + ObMenuFrame* menu_frame_under(gint x, gint y); + ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y); ++gboolean menu_entry_frame_x_not_in_bullet(ObMenuFrame* frame, gint x /* local */); + + void menu_entry_frame_show_submenu(ObMenuEntryFrame *self); ++gboolean menu_frame_show(ObMenuFrame *self); + + void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state); + diff --git a/rc.xml b/rc.xml new file mode 100644 index 000000000000..c6db0703d8c9 --- /dev/null +++ b/rc.xml @@ -0,0 +1,76 @@ +<?xml version="1.0"?> +<openbox_config xmlns="http://openbox.org/3.4/rc"> + + <theme> +<!-- By default iconified windows appears in openbox tasklists + regardless of _NET_WM_STATE_SKIP_TASKBAR hint. + Set "strictSkipTaskbar" to "yes" for override this (nonstandard) behavior. --> + <strictSkipTaskbar>no</strictSkipTaskbar> + </theme> + <mouse> + <context name="Desktop"> + <mousebind action="Click" button="Up"> + <action name="DesktopPrevious"/> + </mousebind> + <mousebind action="Click" button="Down"> + <action name="DesktopNext"/> + </mousebind> + <mousebind action="Click" button="W-Up"> + <action name="DesktopPrevious"/> + </mousebind> + <mousebind action="Click" button="W-Down"> + <action name="DesktopNext"/> + </mousebind> + <mousebind action="Click" button="S-Up"> + <action name="Execute"> + <command>amixer set Master 1+</command> + </action> + </mousebind> + <mousebind action="Click" button="S-Down"> + <action name="Execute"> + <command>amixer set Master 1-</command> + </action> + </mousebind> + </context> + <context name="Root"> + <mousebind action="Press" button="Middle"> + <action name="ShowMenu"> + <menu>client-list-combined-menu</menu> + </action> + </mousebind> + <mousebind action="Press" button="Right"> + <action name="ShowMenu"> + <menu>root-menu</menu> + </action> + </mousebind> + </context> + +<!-- edges --> + <context name="ScreenTopLeft"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenTop"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenTopRight"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenRight"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenBottomRight"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenBottom"> <import>Root</import> <import>Desktop</import> </context> + <context name="ScreenBottomLeft"> + <import>Root</import> <import>Desktop</import> + <mousebind action="Press" button="Left"> + <action name="ShowMenu"> + <menu>desktop-app-menu</menu> + </action> + </mousebind> + </context> +<!-- edges end --> + + </mouse> + + <menu> + <file>menu.xml</file> +<!-- When the topmenu appears to be set first layout --> + <TopMenuKbdGroup>0</TopMenuKbdGroup> + +<!-- Allow utf8 menu accelerator keys --> + <utf8Enabled>yes</utf8Enabled> + + </menu> +</openbox_config> diff --git a/strict_skip_taskbar.patch b/strict_skip_taskbar.patch new file mode 100644 index 000000000000..3ffc16a41042 --- /dev/null +++ b/strict_skip_taskbar.patch @@ -0,0 +1,53 @@ +commit 3600f9b81b7987d4f777d6218e23e7b2764878ae +Author: Alexey Korop <avkorop@i.ua> +Date: Tue Mar 31 20:30:28 2015 +0300 + + strict_skip_taskbar + +diff --git a/openbox/config.c b/openbox/config.c +index 5d2408f..81b542c 100644 +--- a/openbox/config.c ++++ b/openbox/config.c +@@ -49,6 +49,7 @@ StrutPartial config_margins; + gchar *config_theme; + gboolean config_theme_keepborder; + guint config_theme_window_list_icon_size; ++gboolean config_theme_strict_skip_taskbar; + + gchar *config_title_layout; + +@@ -735,6 +736,8 @@ static void parse_theme(xmlNodePtr node, gpointer d) + config_theme_window_list_icon_size = 16; + else if (config_theme_window_list_icon_size > 96) + config_theme_window_list_icon_size = 96; ++ if ((n = obt_xml_find_node(node, "strictSkipTaskbar"))) ++ config_theme_strict_skip_taskbar = obt_xml_node_bool(n); + } + + for (n = obt_xml_find_node(node, "font"); +diff --git a/openbox/config.h b/openbox/config.h +index e70ccab..45f8adf 100644 +--- a/openbox/config.h ++++ b/openbox/config.h +@@ -152,6 +152,8 @@ extern gchar *config_title_layout; + extern gboolean config_animate_iconify; + /*! Size of icons in focus switching dialogs */ + extern guint config_theme_window_list_icon_size; ++/*! not show in tasklist iconified windows with _NET_WM_STATE_SKIP_TASKBAR hint */ ++extern gboolean config_theme_strict_skip_taskbar; + + /*! The font for the active window's title */ + extern RrFont *config_font_activewindow; +diff --git a/openbox/focus.c b/openbox/focus.c +index a4626bf..257cce6 100644 +--- a/openbox/focus.c ++++ b/openbox/focus.c +@@ -365,7 +365,7 @@ gboolean focus_valid_target(ObClient *ft, + not be long-lasting windows */ + ok = ok && (!ft->skip_taskbar || + (ft->modal || user_request || +- (ft->iconic && !ft->parents) || ++ (!config_theme_strict_skip_taskbar && ft->iconic && !ft->parents) || + ft->demands_attention || + ft->type == OB_CLIENT_TYPE_DIALOG)); + diff --git a/topmenu_kbd_group.patch b/topmenu_kbd_group.patch new file mode 100644 index 000000000000..6b3302ca9cdd --- /dev/null +++ b/topmenu_kbd_group.patch @@ -0,0 +1,59 @@ +diff --git a/data/rc.xsd b/data/rc.xsd +--- a/data/rc.xsd ++++ b/data/rc.xsd +@@ -218,6 +218,7 @@ + <xsd:complexType name="menu"> + <xsd:sequence> + <xsd:element maxOccurs="unbounded" name="file" type="xsd:string"/> ++ <xsd:element minOccurs="0" name="TopMenuKbdGroup" type="xsd:integer"/> + <xsd:element minOccurs="0" name="hideDelay" type="xsd:integer"/> + <xsd:element minOccurs="0" name="middle" type="ob:bool"/> + <xsd:element minOccurs="0" name="utf8Enabled" type="ob:bool"/> +diff --git a/openbox/config.c b/openbox/config.c +--- a/openbox/config.c ++++ b/openbox/config.c +@@ -92,6 +92,7 @@ gint config_mouse_dclicktime; + gint config_mouse_screenedgetime; + gboolean config_mouse_screenedgewarp; + ++guint config_menu_topmenu_kbd_group; + guint config_menu_hide_delay; + gboolean config_menu_middle; + guint config_submenu_show_delay; +@@ -937,6 +938,8 @@ static void parse_menu(xmlNodePtr node, gpointer d) + xmlNodePtr n; + node = node->children; + ++ if ((n = obt_xml_find_node(node, "TopMenuKbdGroup"))) ++ config_menu_topmenu_kbd_group = obt_xml_node_int(n) + 1; + if ((n = obt_xml_find_node(node, "hideDelay"))) + config_menu_hide_delay = obt_xml_node_int(n); + if ((n = obt_xml_find_node(node, "middle"))) +diff --git a/openbox/config.h b/openbox/config.h +--- a/openbox/config.h ++++ b/openbox/config.h +@@ -197,6 +197,9 @@ extern gint config_resist_win; + /*! Number of pixels to resist while crossing a screen's edge */ + extern gint config_resist_edge; + ++/*! Incremented by 1 keyboard layout group that must be set when the toplevel menu show. ++0 if not defined */ ++extern guint config_menu_topmenu_kbd_group; + /*! Delay for hiding menu when opening in milliseconds */ + extern guint config_menu_hide_delay; + /*! Center menus vertically about the parent entry */ +diff --git a/openbox/menuframe.c b/openbox/menuframe.c +--- a/openbox/menuframe.c ++++ b/openbox/menuframe.c +@@ -1056,6 +1056,11 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, + e->ignore_enters++; + } + ++ /* set the keyboard layout if specified */ ++ gint n = config_menu_topmenu_kbd_group; ++ if (n) ++ XkbLockGroup(obt_display, XkbUseCoreKbd, n - 1); ++ + return TRUE; + } + diff --git a/topmenu_kbd_group_local.patch b/topmenu_kbd_group_local.patch new file mode 100644 index 000000000000..0167b71c0fa7 --- /dev/null +++ b/topmenu_kbd_group_local.patch @@ -0,0 +1,63 @@ +commit 930d2c1dc7c7ca20defc0ad5540ba628f19adf9f +Author: Alexey Korop <avkorop@i.ua> +Date: Tue Mar 17 08:49:45 2015 +0200 + + topmenu_kbd_group_local.patch + +diff --git a/openbox/menu.c b/openbox/menu.c +index 57de2fb..6eaf7e9 100644 +--- a/openbox/menu.c ++++ b/openbox/menu.c +@@ -373,6 +373,7 @@ static void parse_menu(xmlNodePtr node, gpointer data) + gchar *name = NULL, *title = NULL, *script = NULL; + ObMenu *menu; + ObMenuEntry *e; ++ gint n = 0; + gchar *icon; + GList *keylist = NULL; + gchar *keystring, **keys, **key; +@@ -380,6 +381,9 @@ static void parse_menu(xmlNodePtr node, gpointer data) + if (!obt_xml_attr_string(node, "id", &name)) + goto parse_menu_fail; + ++ if (obt_xml_attr_int(node, "TopMenuKbdGroup", &n)) ++ ++n; ++ + if (obt_xml_attr_string(node, "key", &keystring)) { // global keybind + keys = g_strsplit(keystring, " ", 0); + for (key = keys; *key; ++key) +@@ -393,6 +397,7 @@ static void parse_menu(xmlNodePtr node, gpointer data) + + if ((menu = menu_new(name, title, TRUE, NULL))) { + menu->pipe_creator = state->pipe_creator; ++ menu->topmenu_kbd_group = n; + if (obt_xml_attr_string(node, "execute", &script)) { + menu->execute = obt_paths_expand_tilde(script); + } else { +diff --git a/openbox/menu.h b/openbox/menu.h +index 04dcf10..c048f65 100644 +--- a/openbox/menu.h ++++ b/openbox/menu.h +@@ -59,6 +59,9 @@ struct _ObMenu + gchar *name; + /* Displayed title */ + gchar *title; ++ /* Incremented by 1 keyboard layout group that must be set when this menu show ++ as root level menu. 0 if not defined. */ ++ guint topmenu_kbd_group; + gchar *collate_key; + /*! The shortcut key that would be used to activate this menu if it was + displayed as a submenu */ +diff --git a/openbox/menuframe.c b/openbox/menuframe.c +index b7ca002..9b438f2 100644 +--- a/openbox/menuframe.c ++++ b/openbox/menuframe.c +@@ -1071,6 +1071,8 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, const GravityPoint *pos, + + /* set the keyboard layout if specified */ + gint n = config_menu_topmenu_kbd_group; ++ if (self->menu->topmenu_kbd_group) ++ n = self->menu->topmenu_kbd_group; // prefer this menu setting + if (n) + XkbLockGroup(obt_display, XkbUseCoreKbd, n - 1); + diff --git a/utf8-menu-accelerators.diff b/utf8-menu-accelerators.diff new file mode 100644 index 000000000000..a741eee1743f --- /dev/null +++ b/utf8-menu-accelerators.diff @@ -0,0 +1,166 @@ +diff --git a/data/rc.xml b/data/rc.xml +index a9a7a35..1f66840 100644 +--- a/data/rc.xml ++++ b/data/rc.xml +@@ -637,6 +637,14 @@ + entry in parent menu + if this is a negative value, then the delay is infinite and the + submenu will not be hidden until a different submenu is opened --> ++ <utf8Enabled>no</utf8Enabled> ++ <!-- set to 'yes' to enable utf8 (unicode) support for menu shortcuts ++ this includes automatic selection of first suitable character and ++ manual setting with a prepended underscore --> ++ <utf8AllowGraph>no</utf8AllowGraph> ++ <!-- set to 'yes' (utf8Enabled must also be set to 'yes') to allow the use of ++ any printable utf8 (unicode) character as a menu shortcut ++ by default ('no'), shortcuts are restricted to alphanumeric characters --> + <showIcons>yes</showIcons> + <!-- controls if icons appear in the client-list-(combined-)menu --> + <manageDesktops>yes</manageDesktops> +diff --git a/data/rc.xsd b/data/rc.xsd +index c8f5638..9578b84 100644 +--- a/data/rc.xsd ++++ b/data/rc.xsd +@@ -221,6 +221,8 @@ + <xsd:element maxOccurs="unbounded" name="file" type="xsd:string"/> + <xsd:element minOccurs="0" name="hideDelay" type="xsd:integer"/> + <xsd:element minOccurs="0" name="middle" type="ob:bool"/> ++ <xsd:element minOccurs="0" name="utf8Enabled" type="ob:bool"/> ++ <xsd:element minOccurs="0" name="utf8AllowGraph" type="ob:bool"/> + <xsd:element minOccurs="0" name="submenuShowDelay" type="xsd:integer"/> + <xsd:element minOccurs="0" name="showIcons" type="ob:bool"/> + <xsd:element minOccurs="0" name="manageDesktops" type="ob:bool"/> +diff --git a/openbox/config.c b/openbox/config.c +index 436c555..709c777 100644 +--- a/openbox/config.c ++++ b/openbox/config.c +@@ -98,6 +98,8 @@ guint config_submenu_show_delay; + guint config_submenu_hide_delay; + gboolean config_menu_manage_desktops; + gboolean config_menu_show_icons; ++gboolean config_menu_utf8_enabled; ++gboolean config_menu_utf8_allow_graph; + + GSList *config_menu_files; + +@@ -964,8 +966,13 @@ static void parse_menu(xmlNodePtr node, gpointer d) + config_submenu_hide_delay = obt_xml_node_int(n); + if ((n = obt_xml_find_node(node, "manageDesktops"))) + config_menu_manage_desktops = obt_xml_node_bool(n); ++ if ((n = obt_xml_find_node(node, "utf8Enabled"))) ++ config_menu_utf8_enabled = obt_xml_node_bool(n); ++ if ((n = obt_xml_find_node(node, "utf8AllowGraph"))) ++ config_menu_utf8_allow_graph = obt_xml_node_bool(n); + if ((n = obt_xml_find_node(node, "showIcons"))) { + config_menu_show_icons = obt_xml_node_bool(n); ++ + #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG) + if (config_menu_show_icons) + g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded.")); +@@ -1180,6 +1187,8 @@ void config_startup(ObtXmlInst *i) + config_submenu_show_delay = 100; + config_submenu_hide_delay = 400; + config_menu_manage_desktops = TRUE; ++ config_menu_utf8_enabled = FALSE; ++ config_menu_utf8_allow_graph = FALSE; + config_menu_files = NULL; + config_menu_show_icons = TRUE; + +diff --git a/openbox/config.h b/openbox/config.h +index 5a694c0..d4f5130 100644 +--- a/openbox/config.h ++++ b/openbox/config.h +@@ -210,6 +210,10 @@ extern guint config_submenu_show_delay; + extern guint config_submenu_hide_delay; + /*! Show manage desktops in client_list_menu */ + extern gboolean config_menu_manage_desktops; ++/*! Enable utf8 support in menus */ ++extern gboolean config_menu_utf8_enabled; ++/*! Allow using all graphs as menu shortcuts */ ++extern gboolean config_menu_utf8_allow_graph; + /*! Load & show icons in user-defined menus */ + extern gboolean config_menu_show_icons; + /*! User-specified menu files */ +diff --git a/openbox/menu.c b/openbox/menu.c +index 8804e12..a708b38 100644 +--- a/openbox/menu.c ++++ b/openbox/menu.c +@@ -55,6 +55,7 @@ static void menu_destroy_hash_value(ObMenu *self); + static void parse_menu_item(xmlNodePtr node, gpointer data); + static void parse_menu_separator(xmlNodePtr node, gpointer data); + static void parse_menu(xmlNodePtr node, gpointer data); ++static gboolean is_valid_shortcut(gchar *c); + static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, + gchar **strippedlabel, guint *position, + gboolean *always_show); +@@ -201,6 +202,19 @@ static ObMenu* menu_from_name(gchar *name) + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z')) + ++static gboolean is_valid_shortcut(gchar *c) ++{ ++ gunichar uc; ++ ++ if(!config_menu_utf8_enabled) // unless utf8 support is explicitly enabled in config ++ return VALID_SHORTCUT(*c); // preserve old behaviour ++ ++ uc = g_utf8_get_char_validated(c, MAX(OB_MAX_UTF8_CHAR_SZ, strlen(c))); ++ g_assert(uc > ((gunichar) - 1)); ++ ++ return config_menu_utf8_allow_graph ? g_unichar_isgraph(uc) : g_unichar_isalnum(uc); ++} ++ + static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, + gchar **strippedlabel, guint *position, + gboolean *always_show) +@@ -228,7 +242,7 @@ static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, + i = *strippedlabel; + do { + escape = FALSE; +- i = strchr(i, '_'); ++ i = config_menu_utf8_enabled ? g_utf8_strchr(i, -1, '_') : strchr(i, '_'); + if (i && *(i+1) == '_') { + gchar *j; + +@@ -244,10 +258,16 @@ static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, + if (allow_shortcut && i != NULL) { + /* there is an underscore in the string */ + +- /* you have to use a printable ascii character for shortcuts ++ /* without utf8Enabled: ++ you have to use an alphanumeric ascii character for shortcuts ++ ++ with utf8Enabled: ++ iff not utf8AllowGraph, you have to use an alphanumeric utf8 character ++ else any graph will do (printable character excluding whitespace/formatting ++ + don't allow space either, so you can have like "a _ b" + */ +- if (VALID_SHORTCUT(*(i+1))) { ++ if (is_valid_shortcut(i+1)) { + shortcut = g_unichar_tolower(g_utf8_get_char(i+1)); + *position = i - *strippedlabel; + *always_show = TRUE; +@@ -267,7 +287,7 @@ static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, + instead */ + + for (i = *strippedlabel; *i != '\0'; ++i) +- if (VALID_SHORTCUT(*i)) { ++ if (is_valid_shortcut(i)) { + *position = i - *strippedlabel; + shortcut = g_unichar_tolower(g_utf8_get_char(i)); + break; +diff --git a/openbox/misc.h b/openbox/misc.h +index 750dddd..43b686a 100644 +--- a/openbox/misc.h ++++ b/openbox/misc.h +@@ -19,6 +19,9 @@ + #ifndef __ob__misc_h + #define __ob__misc_h + ++ ++#define OB_MAX_UTF8_CHAR_SZ 4 ++ + /*! The alpha value to use for icons of iconified windows in various places + like the focus cycle popup and client list menus. + Give iconic windows 7/16 alpha. A little under 50%. |