new/better/cleaner scripting interface

This commit is contained in:
Dana Jansens 2003-01-25 16:36:55 +00:00
parent 02d6362111
commit 997f94cf86
16 changed files with 349 additions and 641 deletions

View file

@ -1,6 +1,7 @@
scriptdir = $(libdir)/openbox/python scriptdir = $(libdir)/openbox/python
MAINTAINERCLEANFILES = Makefile.in MAINTAINERCLEANFILES = Makefile.in
script_DATA = config.py builtins.py defaults.py focus.py script_DATA = config.py builtins.py defaults.py focus.py callbacks.py \
focusmodel.py windowplacement.py behavior.py
EXTRA_DIST = $(script_DATA) EXTRA_DIST = $(script_DATA)
distclean-local: distclean-local:

View file

@ -1,334 +1,2 @@
###########################################################################
### Functions that can be used as callbacks for mouse/keyboard bindings ###
###########################################################################
def state_above(data, add=2):
"""Toggles, adds or removes the 'above' state on a window."""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().net_wm_state, data.client.window(), add,
Property_atoms().net_wm_state_above)
def state_below(data, add=2):
"""Toggles, adds or removes the 'below' state on a window."""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().net_wm_state, data.client.window(), add,
Property_atoms().net_wm_state_below)
def state_shaded(data, add=2):
"""Toggles, adds or removes the 'shaded' state on a window."""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().net_wm_state, data.client.window(), add,
Property_atoms().net_wm_state_shaded)
def iconify(data):
"""Iconifies the window on which the event occured"""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().wm_change_state,
data.client.window(), 3) # IconicState
def restore(data):
"""Un-iconifies the window on which the event occured, but does not focus
if. If you want to focus the window too, it is recommended that you
use the activate() function."""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().wm_change_state,
data.client.window(), 1) # NormalState
def close(data):
"""Closes the window on which the event occured"""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().net_close_window, data.client.window(), 0)
def focus(data):
"""Focuses the window on which the event occured"""
if not data.client: return
# !normal windows dont get focus from window enter events
if data.action == EventEnterWindow and not data.client.normal():
return
data.client.focus()
def move(data):
"""Moves the window interactively. This should only be used with
MouseMotion events"""
if not data.client: return
# !normal windows dont get moved
if not data.client.normal(): return
dx = data.xroot - data.pressx
dy = data.yroot - data.pressy
data.client.move(data.press_clientx + dx, data.press_clienty + dy)
def resize(data):
"""Resizes the window interactively. This should only be used with
MouseMotion events"""
if not data.client: return
# !normal windows dont get moved
if not data.client.normal(): return
px = data.pressx
py = data.pressy
dx = data.xroot - px
dy = data.yroot - py
# pick a corner to anchor
if not (resize_nearest or data.context == MC_Grip):
corner = Client.TopLeft
else:
x = px - data.press_clientx
y = py - data.press_clienty
if y < data.press_clientheight / 2:
if x < data.press_clientwidth / 2:
corner = Client.BottomRight
dx *= -1
else:
corner = Client.BottomLeft
dy *= -1
else:
if x < data.press_clientwidth / 2:
corner = Client.TopRight
dx *= -1
else:
corner = Client.TopLeft
data.client.resize(corner,
data.press_clientwidth + dx,
data.press_clientheight + dy);
def restart(data, other = ""):
"""Restarts openbox, optionally starting another window manager."""
openbox.restart(other)
def raise_win(data):
"""Raises the window on which the event occured"""
if not data.client: return
openbox.screen(data.screen).raiseWindow(data.client)
def lower_win(data):
"""Lowers the window on which the event occured"""
if not data.client: return
openbox.screen(data.screen).lowerWindow(data.client)
def toggle_shade(data):
"""Toggles the shade status of the window on which the event occured"""
state_shaded(data)
def shade(data):
"""Shades the window on which the event occured"""
state_shaded(data, 1)
def unshade(data):
"""Unshades the window on which the event occured"""
state_shaded(data, 0)
def change_desktop(data, num):
"""Switches to a specified desktop"""
root = display.screenInfo(data.screen).rootWindow()
send_client_msg(root, Property_atoms().net_current_desktop, root, num)
def next_desktop(data, no_wrap=0):
"""Switches to the next desktop, optionally (by default) cycling around to
the first when going past the last."""
screen = openbox.screen(data.screen)
d = screen.desktop()
n = screen.numDesktops()
if (d < (n-1)):
d = d + 1
elif not no_wrap:
d = 0
change_desktop(data, d)
def prev_desktop(data, no_wrap=0):
"""Switches to the previous desktop, optionally (by default) cycling around
to the last when going past the first."""
screen = openbox.screen(data.screen)
d = screen.desktop()
n = screen.numDesktops()
if (d > 0):
d = d - 1
elif not no_wrap:
d = n - 1
change_desktop(data, d)
def send_to_desktop(data, num):
"""Sends a client to a specified desktop"""
if not data.client: return
send_client_msg(display.screenInfo(data.screen).rootWindow(),
Property_atoms().net_wm_desktop, data.client.window(), num)
def toggle_all_desktops(data):
"""Toggles between sending a client to all desktops and to the current
desktop."""
if not data.client: return
if not data.client.desktop() == 0xffffffff:
send_to_desktop(data, 0xffffffff)
else:
send_to_desktop(data, openbox.screen(data.screen).desktop())
def send_to_all_desktops(data):
"""Sends a client to all desktops"""
if not data.client: return
send_to_desktop(data, 0xffffffff)
def send_to_next_desktop(data, no_wrap=0, follow=1):
"""Sends a window to the next desktop, optionally (by default) cycling
around to the first when going past the last. Also optionally moving to
the new desktop after sending the window."""
if not data.client: return
screen = openbox.screen(data.screen)
d = screen.desktop()
n = screen.numDesktops()
if (d < (n-1)):
d = d + 1
elif not no_wrap:
d = 0
send_to_desktop(data, d)
if follow:
change_desktop(data, d)
def send_to_prev_desktop(data, no_wrap=0, follow=1):
"""Sends a window to the previous desktop, optionally (by default) cycling
around to the last when going past the first. Also optionally moving to
the new desktop after sending the window."""
if not data.client: return
screen = openbox.screen(data.screen)
d = screen.desktop()
n = screen.numDesktops()
if (d > 0):
d = d - 1
elif not no_wrap:
d = n - 1
send_to_desktop(data, d)
if follow:
change_desktop(data, d)
#########################################
### Convenience functions for scripts ###
#########################################
def execute(bin, screen = 0):
"""Executes a command on the specified screen. It is recommended that you
use this call instead of a python system call. If the specified screen
is beyond your range of screens, the default is used instead."""
openbox.execute(screen, bin)
def setup_click_focus(click_raise = 1):
"""Sets up for focusing windows by clicking on or in the window.
Optionally, clicking on or in a window can raise the window to the
front of its stacking layer."""
mbind("Left", MC_Titlebar, MousePress, focus)
mbind("Left", MC_Handle, MousePress, focus)
mbind("Left", MC_Grip, MousePress, focus)
mbind("Left", MC_Window, MousePress, focus)
#mbind("A-Left", MC_Frame, MousePress, focus)
if click_raise:
mbind("Left", MC_Titlebar, MousePress, raise_win)
mbind("Left", MC_Handle, MousePress, raise_win)
mbind("Left", MC_Grip, MousePress, raise_win)
mbind("Left", MC_Window, MousePress, raise_win)
def setup_sloppy_focus(click_focus = 1, click_raise = 0):
"""Sets up for focusing windows when the mouse pointer enters them.
Optionally, clicking on or in a window can focus it if your pointer
ends up inside a window without focus. Also, optionally, clicking on or
in a window can raise the window to the front of its stacking layer."""
ebind(EventEnterWindow, focus)
if click_focus:
setup_click_focus(click_raise)
def setup_window_clicks():
"""Sets up the default bindings for various mouse buttons for various
contexts.
This includes:
* Alt-left drag anywhere on a window will move it
* Alt-right drag anywhere on a window will resize it
* Left drag on a window's titlebar/handle will move it
* Left drag on a window's handle grips will resize it
* Alt-left press anywhere on a window's will raise it to the front of
its stacking layer.
* Left press on a window's titlebar/handle will raise it to the front
of its stacking layer.
* Alt-middle click anywhere on a window's will lower it to the bottom
of its stacking layer.
* Middle click on a window's titlebar/handle will lower it to the
bottom of its stacking layer.
* Double-left click on a window's titlebar will toggle shading it
"""
mbind("A-Left", MC_Frame, MouseMotion, move)
mbind("Left", MC_Titlebar, MouseMotion, move)
mbind("Left", MC_Handle, MouseMotion, move)
mbind("A-Right", MC_Frame, MouseMotion, resize)
mbind("Left", MC_Grip, MouseMotion, resize)
mbind("Left", MC_Titlebar, MousePress, raise_win)
mbind("Left", MC_Handle, MousePress, raise_win)
mbind("A-Left", MC_Frame, MousePress, raise_win)
mbind("A-Middle", MC_Frame, MouseClick, lower_win)
mbind("Middle", MC_Titlebar, MouseClick, lower_win)
mbind("Middle", MC_Handle, MouseClick, lower_win)
mbind("Left", MC_Titlebar, MouseDoubleClick, toggle_shade)
def setup_window_buttons():
"""Sets up the default behaviors for the buttons in the window titlebar."""
mbind("Left", MC_AllDesktopsButton, MouseClick, toggle_all_desktops)
mbind("Left", MC_CloseButton, MouseClick, close)
mbind("Left", MC_IconifyButton, MouseClick, iconify)
def setup_scroll():
"""Sets up the default behaviors for the mouse scroll wheel.
This includes:
* scrolling on a window titlebar will shade/unshade it
* alt-scrolling anywhere will switch to the next/previous desktop
* control-alt-scrolling on a window will send it to the next/previous
desktop, and switch to the desktop with the window
"""
mbind("Up", MC_Titlebar, MouseClick, shade)
mbind("Down", MC_Titlebar, MouseClick, unshade)
mbind("A-Up", MC_Frame, MouseClick, next_desktop)
mbind("A-Up", MC_Root, MouseClick, next_desktop)
mbind("A-Down", MC_Frame, MouseClick, prev_desktop)
mbind("A-Down", MC_Root, MouseClick, prev_desktop)
mbind("C-A-Up", MC_Frame, MouseClick, send_to_next_desktop)
mbind("C-A-Down", MC_Frame, MouseClick, send_to_prev_desktop)
def setup_fallback_focus():
"""Sets up a focus fallback routine so that when no windows are focused,
the last window to have focus on the desktop will be focused."""
global ob_focus_fallback # see focus.py
ob_focus_fallback = 1
############################################################################
### Window placement algorithms, choose one of these and ebind it to the ###
### EventPlaceWindow action. ###
############################################################################
ob_rand = None
import random
def placewindows_random(data):
if not data.client: return
client_area = data.client.area()
frame_size = data.client.frame.size()
screen_area = openbox.screen(data.screen).area()
width = screen_area.width() - (client_area.width() +
frame_size.left + frame_size.right)
height = screen_area.height() - (client_area.height() +
frame_size.top + frame_size.bottom)
global ob_rand
if not ob_rand: ob_rand = random.Random()
x = ob_rand.randrange(screen_area.x(), width-1)
y = ob_rand.randrange(screen_area.y(), height-1)
data.client.move(x, y)
print "Loaded builtins.py" print "Loaded builtins.py"

View file

@ -1,36 +1,43 @@
import focus # add some default focus handling and cycling functions
import focusmodel # default focus models
import behavior # defines default behaviors for interaction with windows
import callbacks # a lib of functions that can be used as binding callbacks
import windowplacement # use a routine in here to place windows
# try focus something when nothing is focused
focus.fallback = 1
# set up the mouse buttons # set up the mouse buttons
setup_sloppy_focus() focusmodel.setup_sloppy_focus()
setup_window_clicks() behavior.setup_window_clicks()
setup_window_buttons() behavior.setup_window_buttons()
setup_scroll() behavior.setup_scroll()
# set up focus fallback so im not left with nothing focused all the time
setup_fallback_focus()
# my window placement algorithm # my window placement algorithm
ebind(EventPlaceWindow, placewindows_random) ob.ebind(ob.EventAction.PlaceWindow, windowplacement.random)
# run xterm from root clicks # run xterm from root clicks
mbind("Left", MC_Root, MouseClick, lambda(d): execute("xterm")) ob.mbind("Left", ob.MouseContext.Root, ob.MouseAction.Click,
lambda(d): ob.execute("xterm", d.screen))
kbind(["A-F4"], KC_All, close) ob.kbind(["A-F4"], ob.KeyContext.All, callbacks.close)
# desktop changing bindings # desktop changing bindings
kbind(["C-1"], KC_All, lambda(d): change_desktop(d, 0)) ob.kbind(["C-1"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 0))
kbind(["C-2"], KC_All, lambda(d): change_desktop(d, 1)) ob.kbind(["C-2"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 1))
kbind(["C-3"], KC_All, lambda(d): change_desktop(d, 2)) ob.kbind(["C-3"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 2))
kbind(["C-4"], KC_All, lambda(d): change_desktop(d, 3)) ob.kbind(["C-4"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 3))
kbind(["C-A-Right"], KC_All, lambda(d): next_desktop(d)) ob.kbind(["C-A-Right"], ob.KeyContext.All,
kbind(["C-A-Left"], KC_All, lambda(d): prev_desktop(d)) lambda(d): callbacks.next_desktop(d))
ob.kbind(["C-A-Left"], ob.KeyContext.All,
lambda(d): callbacks.prev_desktop(d))
kbind(["C-S-A-Right"], KC_All, lambda(d): send_to_next_desktop(d)) ob.kbind(["C-S-A-Right"], ob.KeyContext.All,
kbind(["C-S-A-Left"], KC_All, lambda(d): send_to_prev_desktop(d)) lambda(d): callbacks.send_to_next_desktop(d))
ob.kbind(["C-S-A-Left"], ob.KeyContext.All,
lambda(d): callbacks.send_to_prev_desktop(d))
# focus new windows # focus new windows
def focusnew(data): ob.ebind(ob.EventAction.NewWindow, callbacks.focus)
if not data.client: return
if data.client.normal():
focus(data)
ebind(EventNewWindow, focusnew)
print "Loaded defaults.py" print "Loaded defaults.py"

View file

@ -2,131 +2,150 @@
### Functions for helping out with your window focus. ### ### Functions for helping out with your window focus. ###
########################################################################### ###########################################################################
# raise the window also when it is focused ###########################################################################
ob_focus_raise = 1 ### Options that affect the behavior of the focus module. ###
# send focus somewhere when nothing is left with the focus if possible ### ###
ob_focus_fallback = 0 # raise the window also when it is focused ###
cycle_raise = 1 ###
# raise as you cycle in stacked mode ###
stacked_cycle_raise = 0 ###
# send focus somewhere when nothing is left with the focus, if possible ###
fallback = 0 ###
### ###
###########################################################################
import ob
# maintain a list of clients, stacked in focus order # maintain a list of clients, stacked in focus order
ob_clients = [] _clients = []
# maintaint he current focused window # maintaint he current focused window
ob_doing_stacked = 0 _doing_stacked = 0
def ob_new_win(data): def _new_win(data):
global ob_clients global _clients
global ob_doing_stacked global _doing_stacked
global ob_cyc_w; global _cyc_w;
if ob_doing_stacked: if _doing_stacked:
ob_clients.insert(ob_clients.index(ob_cyc_w), data.client.window()) _clients.insert(_clients.index(_cyc_w), data.client.window())
else: else:
if not len(ob_clients): if not len(_clients):
ob_clients.append(data.client.window()) _clients.append(data.client.window())
else: else:
ob_clients.insert(1, data.client.window()) # insert in 2nd slot _clients.insert(1, data.client.window()) # insert in 2nd slot
def ob_close_win(data): def _close_win(data):
global ob_clients global _clients
global ob_cyc_w; global _cyc_w;
global ob_doing_stacked global _doing_stacked
if not ob_doing_stacked: if not _doing_stacked:
# not in the middle of stacked cycling, so who cares # not in the middle of stacked cycling, so who cares
ob_clients.remove(data.client.window()) _clients.remove(data.client.window())
else: else:
# have to fix the cycling if we remove anything # have to fix the cycling if we remove anything
win = data.client.window() win = data.client.window()
if ob_cyc_w == win: if _cyc_w == win:
do_stacked_cycle(data) # cycle off the window first _do_stacked_cycle(data) # cycle off the window first
ob_clients.remove(win) _clients.remove(win)
def ob_focused(data): def _focused(data):
global ob_clients global _clients
global ob_doing_stacked global _doing_stacked
global ob_cyc_w global _cyc_w
if data.client: if data.client:
if not ob_doing_stacked: # only move the window when we're not cycling if not _doing_stacked: # only move the window when we're not cycling
win = data.client.window() win = data.client.window()
# move it to the top # move it to the top
ob_clients.remove(win) _clients.remove(win)
ob_clients.insert(0, win) _clients.insert(0, win)
else: # if we are cycling, then update our pointer else: # if we are cycling, then update our pointer
ob_cyc_w = data.client.window() _cyc_w = data.client.window()
elif ob_focus_fallback: elif fallback:
# pass around focus # pass around focus
desktop = openbox.screen(ob_cyc_screen).desktop() desktop = ob.openbox.screen(_cyc_screen).desktop()
for w in ob_clients: for w in _clients:
client = openbox.findClient(w) client = ob.openbox.findClient(w)
if client and (client.desktop() == desktop and \ if client and (client.desktop() == desktop and \
client.normal() and client.focus()): client.normal() and client.focus()):
break break
ebind(EventNewWindow, ob_new_win) _cyc_mask = 0
ebind(EventCloseWindow, ob_close_win) _cyc_key = 0
ebind(EventFocus, ob_focused) _cyc_w = 0 # last window cycled to
_cyc_screen = 0
ob_cyc_mask = 0 def _do_stacked_cycle(data, forward):
ob_cyc_key = 0 global _cyc_w
ob_cyc_w = 0 # last window cycled to global stacked_cycle_raise
ob_cyc_screen = 0 global _clients
def do_stacked_cycle(data): clients = _clients[:] # make a copy
global ob_cyc_w
if not forward:
clients.reverse()
try: try:
i = ob_clients.index(ob_cyc_w) + 1 i = clients.index(_cyc_w) + 1
except ValueError: except ValueError:
i = 0 i = 1
clients = clients[i:] + clients[:i]
clients = ob_clients[i:] + ob_clients[:i] desktop = ob.openbox.screen(data.screen).desktop()
for w in clients: for w in clients:
client = openbox.findClient(w) client = ob.openbox.findClient(w)
if client and (client.desktop() == desktop and \ if client and (client.desktop() == desktop and \
client.normal() and client.focus()): client.normal() and client.focus()):
if stacked_cycle_raise:
ob.openbox.screen(data.screen).raiseWindow(client)
return return
def focus_next_stacked_grab(data): def _focus_stacked_ungrab(data):
global ob_cyc_mask; global _cyc_mask;
global ob_cyc_key; global _cyc_key;
global ob_cyc_w; global _doing_stacked;
global ob_doing_stacked;
if data.action == EventKeyRelease: if data.action == ob.KeyAction.Release:
# have all the modifiers this started with been released? # have all the modifiers this started with been released?
if not ob_cyc_mask & data.state: if not _cyc_mask & data.state:
kungrab() # ungrab ourself ob.kungrab() # ungrab ourself
ob_doing_stacked = 0; _doing_stacked = 0;
print "UNGRABBED!" if cycle_raise:
else: client = ob.openbox.findClient(_cyc_w)
if ob_cyc_key == data.key: if client:
# the next window to try focusing in ob_clients[ob_cyc_i] ob.openbox.screen(data.screen).raiseWindow(client)
print "CYCLING!!"
do_stacked_cycle(data)
def focus_next_stacked(data, forward=1): def focus_next_stacked(data, forward=1):
global ob_cyc_mask """Focus the next (or previous, with forward=0) window in a stacked
global ob_cyc_key order."""
global ob_cyc_w global _cyc_mask
global ob_cyc_screen global _cyc_key
global ob_doing_stacked global _cyc_w
ob_cyc_mask = data.state global _cyc_screen
ob_cyc_key = data.key global _doing_stacked
ob_cyc_w = 0
ob_cyc_screen = data.screen
ob_doing_stacked = 1
kgrab(data.screen, focus_next_stacked_grab) if _doing_stacked:
print "GRABBED!" if _cyc_key == data.key:
focus_next_stacked_grab(data) # start with the first press _do_stacked_cycle(data,forward)
else:
_cyc_mask = data.state
_cyc_key = data.key
_cyc_w = 0
_cyc_screen = data.screen
_doing_stacked = 1
ob.kgrab(data.screen, _focus_stacked_ungrab)
focus_next_stacked(data, forward) # start with the first press
def focus_prev_stacked(data): def focus_prev_stacked(data):
return """Focus the previous window in a stacked order."""
focus_next_stacked(data, forward=0)
def focus_next(data, num=1, forward=1): def focus_next(data, num=1, forward=1):
"""Focus the next (or previous, with forward=0) window in a linear """Focus the next (or previous, with forward=0) window in a linear
order.""" order."""
screen = openbox.screen(data.screen) screen = ob.openbox.screen(data.screen)
count = screen.clientCount() count = screen.clientCount()
if not count: return # no clients if not count: return # no clients
@ -156,7 +175,7 @@ def focus_next(data, num=1, forward=1):
if client.normal() and \ if client.normal() and \
(client.desktop() == curdesk or client.desktop() == 0xffffffff)\ (client.desktop() == curdesk or client.desktop() == 0xffffffff)\
and client.focus(): and client.focus():
if ob_focus_raise: if cycle_raise:
screen.raiseWindow(client) screen.raiseWindow(client)
return return
if forward: if forward:
@ -172,4 +191,8 @@ def focus_prev(data, num=1):
focus_next(data, num, forward=0) focus_next(data, num, forward=0)
ob.ebind(ob.EventAction.NewWindow, _new_win)
ob.ebind(ob.EventAction.CloseWindow, _close_win)
ob.ebind(ob.EventAction.Focus, _focused)
print "Loaded focus.py" print "Loaded focus.py"

View file

@ -23,7 +23,7 @@ openbox3_SOURCES= actions.cc client.cc frame.cc openbox.cc screen.cc \
openbox_wrap.cc openbox_wrap.cc
openbox3_LDFLAGS= $(PYTHON_LDFLAGS) openbox3_LDFLAGS= $(PYTHON_LDFLAGS)
script_DATA = openbox.py script_DATA = ob.py
EXTRA_DIST = $(script_DATA) EXTRA_DIST = $(script_DATA)

View file

@ -88,14 +88,14 @@ void Actions::buttonPressHandler(const XButtonEvent &e)
else else
screen = otk::display->findScreen(e.root)->screen(); screen = otk::display->findScreen(e.root)->screen();
MouseData data(screen, c, e.time, state, e.button, w->mcontext(), MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
MousePress); MouseAction::Press);
openbox->bindings()->fireButton(&data); openbox->bindings()->fireButton(&data);
if (_button) return; // won't count toward CLICK events if (_button) return; // won't count toward CLICK events
_button = e.button; _button = e.button;
if (w->mcontext() == MC_Window) { if (w->mcontext() == MouseContext::Window) {
/* /*
Because of how events are grabbed on the client window, we can't get Because of how events are grabbed on the client window, we can't get
ButtonRelease events, so instead we simply manufacture them here, so that ButtonRelease events, so instead we simply manufacture them here, so that
@ -143,7 +143,7 @@ void Actions::buttonReleaseHandler(const XButtonEvent &e)
else else
screen = otk::display->findScreen(e.root)->screen(); screen = otk::display->findScreen(e.root)->screen();
MouseData data(screen, c, e.time, state, e.button, w->mcontext(), MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
MouseClick); MouseAction::Click);
openbox->bindings()->fireButton(&data); openbox->bindings()->fireButton(&data);
@ -156,7 +156,7 @@ void Actions::buttonReleaseHandler(const XButtonEvent &e)
_release.win == e.window && _release.button == e.button) { _release.win == e.window && _release.button == e.button) {
// run the DOUBLECLICK python hook // run the DOUBLECLICK python hook
data.action = MouseDoubleClick; data.action = MouseAction::DoubleClick;
openbox->bindings()->fireButton(&data); openbox->bindings()->fireButton(&data);
// reset so you cant triple click for 2 doubleclicks // reset so you cant triple click for 2 doubleclicks
@ -183,7 +183,7 @@ void Actions::enterHandler(const XCrossingEvent &e)
screen = c->screen(); screen = c->screen();
else else
screen = otk::display->findScreen(e.root)->screen(); screen = otk::display->findScreen(e.root)->screen();
EventData data(screen, c, EventEnterWindow, e.state); EventData data(screen, c, EventAction::EnterWindow, e.state);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
} }
@ -199,14 +199,13 @@ void Actions::leaveHandler(const XCrossingEvent &e)
screen = c->screen(); screen = c->screen();
else else
screen = otk::display->findScreen(e.root)->screen(); screen = otk::display->findScreen(e.root)->screen();
EventData data(screen, c, EventLeaveWindow, e.state); EventData data(screen, c, EventAction::LeaveWindow, e.state);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
} }
void Actions::keyPressHandler(const XKeyEvent &e) void Actions::keyPressHandler(const XKeyEvent &e)
{ {
printf("press\n");
otk::EventHandler::keyPressHandler(e); otk::EventHandler::keyPressHandler(e);
// kill off the Button1Mask etc, only want the modifiers // kill off the Button1Mask etc, only want the modifiers
@ -214,13 +213,12 @@ void Actions::keyPressHandler(const XKeyEvent &e)
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask); Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
openbox->bindings()-> openbox->bindings()->
fireKey(otk::display->findScreen(e.root)->screen(), fireKey(otk::display->findScreen(e.root)->screen(),
state, e.keycode, e.time, EventKeyPress); state, e.keycode, e.time, KeyAction::Press);
} }
void Actions::keyReleaseHandler(const XKeyEvent &e) void Actions::keyReleaseHandler(const XKeyEvent &e)
{ {
printf("release\n");
otk::EventHandler::keyReleaseHandler(e); otk::EventHandler::keyReleaseHandler(e);
// kill off the Button1Mask etc, only want the modifiers // kill off the Button1Mask etc, only want the modifiers
@ -248,7 +246,7 @@ void Actions::keyReleaseHandler(const XKeyEvent &e)
openbox->bindings()-> openbox->bindings()->
fireKey(otk::display->findScreen(e.root)->screen(), fireKey(otk::display->findScreen(e.root)->screen(),
state, e.keycode, e.time, EventKeyRelease); state, e.keycode, e.time, KeyAction::Release);
} }
@ -301,8 +299,9 @@ void Actions::motionHandler(const XMotionEvent &e)
screen = c->screen(); screen = c->screen();
else else
screen = otk::display->findScreen(e.root)->screen(); screen = otk::display->findScreen(e.root)->screen();
MouseData data(screen, c, e.time, state, button, w->mcontext(), MouseMotion, MouseData data(screen, c, e.time, state, button, w->mcontext(),
x_root, y_root, _posqueue[0]->pos, _posqueue[0]->clientarea); MouseAction::Motion, x_root, y_root,
_posqueue[0]->pos, _posqueue[0]->clientarea);
openbox->bindings()->fireButton(&data); openbox->bindings()->fireButton(&data);
} }
@ -322,7 +321,7 @@ void Actions::xkbHandler(const XkbEvent &e)
screen = c->screen(); screen = c->screen();
else else
screen = openbox->focusedScreen()->number(); screen = openbox->focusedScreen()->number();
EventData data(screen, c, EventBell, 0); EventData data(screen, c, EventAction::Bell, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
break; break;
} }

View file

@ -344,7 +344,9 @@ void Bindings::removeAllKeys()
void Bindings::grabKeys(bool grab) void Bindings::grabKeys(bool grab)
{ {
for (int i = 0; i < openbox->screenCount(); ++i) { for (int i = 0; i < ScreenCount(**otk::display); ++i) {
Screen *sc = openbox->screen(i);
if (!sc) continue; // not a managed screen
Window root = otk::display->screenInfo(i)->rootWindow(); Window root = otk::display->screenInfo(i)->rootWindow();
KeyBindingTree *p = _curpos->first_child; KeyBindingTree *p = _curpos->first_child;
@ -377,18 +379,13 @@ bool Bindings::grabKeyboard(int screen, PyObject *callback)
assert(callback); assert(callback);
if (_keybgrab_callback) return false; // already grabbed if (_keybgrab_callback) return false; // already grabbed
int i; if (!openbox->screen(screen))
for (i = 0; i < openbox->screenCount(); ++i) return false; // the screen is not managed
if (openbox->screen(screen)->number() == screen)
break;
if (i >= openbox->screenCount())
return false; // couldn't find the screen.. it's not managed
Window root = otk::display->screenInfo(i)->rootWindow(); Window root = otk::display->screenInfo(screen)->rootWindow();
if (XGrabKeyboard(**otk::display, root, false, GrabModeAsync, if (XGrabKeyboard(**otk::display, root, false, GrabModeAsync,
GrabModeSync, CurrentTime)) GrabModeAsync, CurrentTime))
return false; return false;
printf("****GRABBED****\n");
_keybgrab_callback = callback; _keybgrab_callback = callback;
return true; return true;
} }
@ -400,51 +397,50 @@ void Bindings::ungrabKeyboard()
_keybgrab_callback = 0; _keybgrab_callback = 0;
XUngrabKeyboard(**otk::display, CurrentTime); XUngrabKeyboard(**otk::display, CurrentTime);
printf("****UNGRABBED****\n");
} }
void Bindings::fireKey(int screen, unsigned int modifiers, unsigned int key, void Bindings::fireKey(int screen, unsigned int modifiers, unsigned int key,
Time time, KeyAction action) Time time, KeyAction::KA action)
{ {
if (_keybgrab_callback) { if (_keybgrab_callback) {
Client *c = openbox->focusedClient(); Client *c = openbox->focusedClient();
KeyData data(screen, c, time, modifiers, key, action); KeyData data(screen, c, time, modifiers, key, action);
python_callback(_keybgrab_callback, &data); python_callback(_keybgrab_callback, &data);
} else { }
// KeyRelease events only occur during keyboard grabs
if (action == EventKeyRelease) return;
if (key == _resetkey.key && modifiers == _resetkey.modifiers) { // KeyRelease events only occur during keyboard grabs
resetChains(this); if (action == KeyAction::Release) return;
} else {
KeyBindingTree *p = _curpos->first_child; if (key == _resetkey.key && modifiers == _resetkey.modifiers) {
while (p) { resetChains(this);
if (p->binding.key == key && p->binding.modifiers == modifiers) { } else {
if (p->chain) { KeyBindingTree *p = _curpos->first_child;
if (_timer) while (p) {
delete _timer; if (p->binding.key == key && p->binding.modifiers == modifiers) {
_timer = new otk::Timer(5000, // 5 second timeout if (p->chain) {
(otk::Timer::TimeoutHandler)resetChains, if (_timer)
this); delete _timer;
// grab the server here to make sure no key pressed go missed _timer = new otk::Timer(5000, // 5 second timeout
otk::display->grab(); (otk::Timer::TimeoutHandler)resetChains,
grabKeys(false); this);
_curpos = p; // grab the server here to make sure no key pressed go missed
grabKeys(true); otk::display->grab();
otk::display->ungrab(); grabKeys(false);
} else { _curpos = p;
Client *c = openbox->focusedClient(); grabKeys(true);
KeyData data(screen, c, time, modifiers, key, action); otk::display->ungrab();
CallbackList::iterator it, end = p->callbacks.end(); } else {
for (it = p->callbacks.begin(); it != end; ++it) Client *c = openbox->focusedClient();
python_callback(*it, &data); KeyData data(screen, c, time, modifiers, key, action);
resetChains(this); CallbackList::iterator it, end = p->callbacks.end();
} for (it = p->callbacks.begin(); it != end; ++it)
break; python_callback(*it, &data);
resetChains(this);
} }
p = p->next_sibling; break;
} }
p = p->next_sibling;
} }
} }
} }
@ -464,10 +460,10 @@ void Bindings::resetChains(Bindings *self)
} }
bool Bindings::addButton(const std::string &but, MouseContext context, bool Bindings::addButton(const std::string &but, MouseContext::MC context,
MouseAction action, PyObject *callback) MouseAction::MA action, PyObject *callback)
{ {
assert(context >= 0 && context < NUM_MOUSE_CONTEXT); assert(context >= 0 && context < MouseContext::NUM_MOUSE_CONTEXT);
Binding b(0,0); Binding b(0,0);
if (!translate(but, b, false)) if (!translate(but, b, false))
@ -491,8 +487,9 @@ bool Bindings::addButton(const std::string &but, MouseContext context,
bind->binding.modifiers = b.modifiers; bind->binding.modifiers = b.modifiers;
_buttons[context].push_back(bind); _buttons[context].push_back(bind);
// grab the button on all clients // grab the button on all clients
for (int sn = 0; sn < openbox->screenCount(); ++sn) { for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
Screen *s = openbox->screen(sn); Screen *s = openbox->screen(sn);
if (!s) continue; // not managed
Client::List::iterator c_it, c_end = s->clients.end(); Client::List::iterator c_it, c_end = s->clients.end();
for (c_it = s->clients.begin(); c_it != c_end; ++c_it) { for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
grabButton(true, bind->binding, context, *c_it); grabButton(true, bind->binding, context, *c_it);
@ -507,39 +504,40 @@ bool Bindings::addButton(const std::string &but, MouseContext context,
void Bindings::removeAllButtons() void Bindings::removeAllButtons()
{ {
for (int i = 0; i < NUM_MOUSE_CONTEXT; ++i) { for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
ButtonBindingList::iterator it, end = _buttons[i].end(); ButtonBindingList::iterator it, end = _buttons[i].end();
for (it = _buttons[i].begin(); it != end; ++it) { for (it = _buttons[i].begin(); it != end; ++it) {
for (int a = 0; a < NUM_MOUSE_ACTION; ++a) { for (int a = 0; a < MouseAction::NUM_MOUSE_ACTION; ++a) {
while (!(*it)->callbacks[a].empty()) { while (!(*it)->callbacks[a].empty()) {
Py_XDECREF((*it)->callbacks[a].front()); Py_XDECREF((*it)->callbacks[a].front());
(*it)->callbacks[a].pop_front(); (*it)->callbacks[a].pop_front();
} }
} }
// ungrab the button on all clients // ungrab the button on all clients
for (int sn = 0; sn < openbox->screenCount(); ++sn) { for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
Screen *s = openbox->screen(sn); Screen *s = openbox->screen(sn);
if (!s) continue; // not managed
Client::List::iterator c_it, c_end = s->clients.end(); Client::List::iterator c_it, c_end = s->clients.end();
for (c_it = s->clients.begin(); c_it != c_end; ++c_it) { for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
grabButton(false, (*it)->binding, (MouseContext)i, *c_it); grabButton(false, (*it)->binding, (MouseContext::MC)i, *c_it);
} }
} }
} }
} }
} }
void Bindings::grabButton(bool grab, const Binding &b, MouseContext context, void Bindings::grabButton(bool grab, const Binding &b,
Client *client) MouseContext::MC context, Client *client)
{ {
Window win; Window win;
int mode = GrabModeAsync; int mode = GrabModeAsync;
unsigned int mask; unsigned int mask;
switch(context) { switch(context) {
case MC_Frame: case MouseContext::Frame:
win = client->frame->window(); win = client->frame->window();
mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask; mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
break; break;
case MC_Window: case MouseContext::Window:
win = client->frame->plate(); win = client->frame->plate();
mode = GrabModeSync; // this is handled in fireButton mode = GrabModeSync; // this is handled in fireButton
mask = ButtonPressMask; // can't catch more than this with Sync mode mask = ButtonPressMask; // can't catch more than this with Sync mode
@ -559,16 +557,16 @@ void Bindings::grabButton(bool grab, const Binding &b, MouseContext context,
void Bindings::grabButtons(bool grab, Client *client) void Bindings::grabButtons(bool grab, Client *client)
{ {
for (int i = 0; i < NUM_MOUSE_CONTEXT; ++i) { for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
ButtonBindingList::iterator it, end = _buttons[i].end(); ButtonBindingList::iterator it, end = _buttons[i].end();
for (it = _buttons[i].begin(); it != end; ++it) for (it = _buttons[i].begin(); it != end; ++it)
grabButton(grab, (*it)->binding, (MouseContext)i, client); grabButton(grab, (*it)->binding, (MouseContext::MC)i, client);
} }
} }
void Bindings::fireButton(MouseData *data) void Bindings::fireButton(MouseData *data)
{ {
if (data->context == MC_Window) { if (data->context == MouseContext::Window) {
// Replay the event, so it goes to the client // Replay the event, so it goes to the client
XAllowEvents(**otk::display, ReplayPointer, data->time); XAllowEvents(**otk::display, ReplayPointer, data->time);
} }
@ -585,13 +583,13 @@ void Bindings::fireButton(MouseData *data)
} }
bool Bindings::addEvent(EventAction action, PyObject *callback) bool Bindings::addEvent(EventAction::EA action, PyObject *callback)
{ {
if (action < 0 || action >= NUM_EVENTS) { if (action < 0 || action >= EventAction::NUM_EVENTS) {
return false; return false;
} }
#ifdef XKB #ifdef XKB
if (action == EventBell && _eventlist[action].empty()) if (action == EventAction::Bell && _eventlist[action].empty())
XkbSelectEvents(**otk::display, XkbUseCoreKbd, XkbSelectEvents(**otk::display, XkbUseCoreKbd,
XkbBellNotifyMask, XkbBellNotifyMask); XkbBellNotifyMask, XkbBellNotifyMask);
#endif // XKB #endif // XKB
@ -600,9 +598,9 @@ bool Bindings::addEvent(EventAction action, PyObject *callback)
return true; return true;
} }
bool Bindings::removeEvent(EventAction action, PyObject *callback) bool Bindings::removeEvent(EventAction::EA action, PyObject *callback)
{ {
if (action < 0 || action >= NUM_EVENTS) { if (action < 0 || action >= EventAction::NUM_EVENTS) {
return false; return false;
} }
@ -613,7 +611,7 @@ bool Bindings::removeEvent(EventAction action, PyObject *callback)
Py_XDECREF(*it); Py_XDECREF(*it);
_eventlist[action].erase(it); _eventlist[action].erase(it);
#ifdef XKB #ifdef XKB
if (action == EventBell && _eventlist[action].empty()) if (action == EventAction::Bell && _eventlist[action].empty())
XkbSelectEvents(**otk::display, XkbUseCoreKbd, XkbSelectEvents(**otk::display, XkbUseCoreKbd,
XkbBellNotifyMask, 0); XkbBellNotifyMask, 0);
#endif // XKB #endif // XKB
@ -624,7 +622,7 @@ bool Bindings::removeEvent(EventAction action, PyObject *callback)
void Bindings::removeAllEvents() void Bindings::removeAllEvents()
{ {
for (int i = 0; i < NUM_EVENTS; ++i) { for (int i = 0; i < EventAction::NUM_EVENTS; ++i) {
while (!_eventlist[i].empty()) { while (!_eventlist[i].empty()) {
Py_XDECREF(_eventlist[i].front()); Py_XDECREF(_eventlist[i].front());
_eventlist[i].pop_front(); _eventlist[i].pop_front();

View file

@ -51,7 +51,7 @@ typedef struct KeyBindingTree {
typedef struct ButtonBinding { typedef struct ButtonBinding {
Binding binding; Binding binding;
CallbackList callbacks[NUM_MOUSE_ACTION]; CallbackList callbacks[MouseAction::NUM_MOUSE_ACTION];
ButtonBinding() : binding(0, 0) {} ButtonBinding() : binding(0, 0) {}
}; };
@ -77,12 +77,12 @@ private:
static void resetChains(Bindings *self); // the timer's timeout function static void resetChains(Bindings *self); // the timer's timeout function
typedef std::list <ButtonBinding*> ButtonBindingList; typedef std::list <ButtonBinding*> ButtonBindingList;
ButtonBindingList _buttons[NUM_MOUSE_CONTEXT]; ButtonBindingList _buttons[MouseContext::NUM_MOUSE_CONTEXT];
void grabButton(bool grab, const Binding &b, MouseContext context, void grabButton(bool grab, const Binding &b, MouseContext::MC context,
Client *client); Client *client);
CallbackList _eventlist[NUM_EVENTS]; CallbackList _eventlist[EventAction::NUM_EVENTS];
PyObject *_keybgrab_callback; PyObject *_keybgrab_callback;
@ -114,7 +114,7 @@ public:
void removeAllKeys(); void removeAllKeys();
void fireKey(int screen, unsigned int modifiers,unsigned int key, Time time, void fireKey(int screen, unsigned int modifiers,unsigned int key, Time time,
KeyAction action); KeyAction::KA action);
void setResetKey(const std::string &key); void setResetKey(const std::string &key);
@ -123,8 +123,8 @@ public:
bool grabKeyboard(int screen, PyObject *callback); bool grabKeyboard(int screen, PyObject *callback);
void ungrabKeyboard(); void ungrabKeyboard();
bool addButton(const std::string &but, MouseContext context, bool addButton(const std::string &but, MouseContext::MC context,
MouseAction action, PyObject *callback); MouseAction::MA action, PyObject *callback);
void grabButtons(bool grab, Client *client); void grabButtons(bool grab, Client *client);
@ -134,10 +134,10 @@ public:
void fireButton(MouseData *data); void fireButton(MouseData *data);
//! Bind a callback for an event //! Bind a callback for an event
bool addEvent(EventAction action, PyObject *callback); bool addEvent(EventAction::EA action, PyObject *callback);
//! Unbind the callback function from an event //! Unbind the callback function from an event
bool removeEvent(EventAction action, PyObject *callback); bool removeEvent(EventAction::EA action, PyObject *callback);
//! Remove all callback functions //! Remove all callback functions
void removeAllEvents(); void removeAllEvents();

View file

@ -133,7 +133,7 @@ void Client::getDesktop()
otk::Property::atoms.cardinal, otk::Property::atoms.cardinal,
(long unsigned*)&_desktop)) { (long unsigned*)&_desktop)) {
#ifdef DEBUG #ifdef DEBUG
printf("DEBUG: Window requested desktop: %ld\n", _desktop); // printf("Window requested desktop: %ld\n", _desktop);
#endif #endif
} }
} }
@ -1181,7 +1181,6 @@ void Client::applyStartupState()
// these are in a carefully crafted order.. // these are in a carefully crafted order..
if (_iconic) { if (_iconic) {
printf("MAP ICONIC\n");
_iconic = false; _iconic = false;
setDesktop(ICONIC_DESKTOP); setDesktop(ICONIC_DESKTOP);
} }
@ -1210,7 +1209,7 @@ void Client::applyStartupState()
void Client::fireUrgent() void Client::fireUrgent()
{ {
// call the python UrgentWindow callbacks // call the python UrgentWindow callbacks
EventData data(_screen, this, EventUrgentWindow, 0); EventData data(_screen, this, EventAction::UrgentWindow, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
} }

View file

@ -147,24 +147,28 @@ Openbox::Openbox(int argc, char **argv)
python_init(argv[0]); python_init(argv[0]);
// load config values // load config values
python_exec(SCRIPTDIR"/config.py"); // load openbox config values //python_exec(SCRIPTDIR"/config.py"); // load openbox config values
// run all of the python scripts // run all of the python scripts
python_exec(SCRIPTDIR"/builtins.py"); // builtin callbacks //python_exec(SCRIPTDIR"/builtins.py"); // builtin callbacks
python_exec(SCRIPTDIR"/focus.py"); // focus helpers //python_exec(SCRIPTDIR"/focus.py"); // focus helpers
// run the user's script or the system defaults if that fails // run the user's script or the system defaults if that fails
if (!python_exec(_scriptfilepath.c_str())) if (!python_exec(_scriptfilepath.c_str()))
python_exec(SCRIPTDIR"/defaults.py"); // system default bahaviors python_exec(SCRIPTDIR"/defaults.py"); // system default bahaviors
// initialize all the screens // initialize all the screens
Screen *screen; for (int i = 0, max = ScreenCount(**otk::display); i < max; ++i) {
int i = _single ? DefaultScreen(**otk::display) : 0; Screen *screen;
int max = _single ? i + 1 : ScreenCount(**otk::display); if (_single && i != DefaultScreen(**otk::display)) {
for (; i < max; ++i) { _screens.push_back(0);
continue;
}
screen = new Screen(i); screen = new Screen(i);
if (screen->managed()) if (screen->managed())
_screens.push_back(screen); _screens.push_back(screen);
else else {
delete screen; delete screen;
_screens.push_back(0);
}
} }
if (_screens.empty()) { if (_screens.empty()) {
@ -390,16 +394,9 @@ void Openbox::setFocusedClient(Client *c)
} }
// call the python Focus callbacks // call the python Focus callbacks
EventData data(_focused_screen->number(), c, EventFocus, 0); EventData data(_focused_screen->number(), c, EventAction::Focus, 0);
_bindings->fireEvent(&data); _bindings->fireEvent(&data);
} }
void Openbox::execute(int screen, const std::string &bin)
{
if (screen >= ScreenCount(**otk::display))
screen = 0;
otk::bexec(bin, otk::display->screenInfo(screen)->displayString());
}
} }

View file

@ -174,19 +174,17 @@ public:
//! Returns the Bindings instance for the window manager //! Returns the Bindings instance for the window manager
inline Bindings *bindings() const { return _bindings; } inline Bindings *bindings() const { return _bindings; }
//! Returns a managed screen //! Returns a managed screen or a null pointer
/*!
ALWAYS check the return value for a non-null, as any unmanaged screens
will return one. This includes screen(0) if the first managed screen is 1.
*/
inline Screen *screen(int num) { inline Screen *screen(int num) {
assert(num >= 0); assert(num < (signed)_screens.size()); assert(num >= 0); assert(num < (signed)ScreenCount(**otk::display));
if (num < 0 || num >= screenCount()) if (num >= (signed)_screens.size()) return 0;
return NULL;
return _screens[num]; return _screens[num];
} }
//! Returns the number of managed screens
inline int screenCount() const {
return (signed)_screens.size();
}
//! Returns the mouse cursors used throughout Openbox //! Returns the mouse cursors used throughout Openbox
inline const Cursors &cursors() const { return _cursors; } inline const Cursors &cursors() const { return _cursors; }
@ -231,9 +229,6 @@ public:
inline void restart(const std::string &bin = "") { inline void restart(const std::string &bin = "") {
_shutdown = true; _restart = true; _restart_prog = bin; _shutdown = true; _restart = true; _restart_prog = bin;
} }
//! Executes a command on a screen
void execute(int screen, const std::string &bin);
}; };
} }

View file

@ -1,6 +1,6 @@
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
%module openbox %module ob
%{ %{
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H

View file

@ -10,7 +10,7 @@
extern "C" { extern "C" {
// The initializer in openbox_wrap.cc // The initializer in openbox_wrap.cc
extern void init_openbox(void); extern void init_ob(void);
} }
namespace ob { namespace ob {
@ -23,21 +23,20 @@ void python_init(char *argv0)
Py_SetProgramName(argv0); Py_SetProgramName(argv0);
Py_Initialize(); Py_Initialize();
// initialize the C python module // initialize the C python module
init_openbox(); init_ob();
// include the openbox directories for python scripts in the sys path // include the openbox directories for python scripts in the sys path
PyRun_SimpleString("import sys"); PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('" SCRIPTDIR "')");
PyRun_SimpleString(const_cast<char*>(("sys.path.append('" + PyRun_SimpleString(const_cast<char*>(("sys.path.append('" +
otk::expandTilde("~/.openbox/python") + otk::expandTilde("~/.openbox/python") +
"')").c_str())); "')").c_str()));
// import the otk and openbox modules into the main namespace PyRun_SimpleString("sys.path.append('" SCRIPTDIR "')");
PyRun_SimpleString("from openbox import *;"); PyRun_SimpleString("import ob;");
// set up convenience global variables // set up convenience global variables
PyRun_SimpleString("openbox = Openbox_instance()"); PyRun_SimpleString("ob.openbox = ob.Openbox_instance()");
PyRun_SimpleString("display = Display_instance()"); PyRun_SimpleString("ob.display = ob.Display_instance()");
// set up access to the python global variables // set up access to the python global variables
PyObject *obmodule = PyImport_AddModule("__main__"); PyObject *obmodule = PyImport_AddModule("config");
obdict = PyModule_GetDict(obmodule); obdict = PyModule_GetDict(obmodule);
} }
@ -93,8 +92,8 @@ bool python_get_stringlist(const char *name, std::vector<otk::ustring> *value)
// Stuff for calling from Python scripts // // Stuff for calling from Python scripts //
// ************************************* // // ************************************* //
PyObject *mbind(const std::string &button, ob::MouseContext context, PyObject *mbind(const std::string &button, ob::MouseContext::MC context,
ob::MouseAction action, PyObject *func) ob::MouseAction::MA action, PyObject *func)
{ {
if (!PyCallable_Check(func)) { if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "Invalid callback function."); PyErr_SetString(PyExc_TypeError, "Invalid callback function.");
@ -102,14 +101,14 @@ PyObject *mbind(const std::string &button, ob::MouseContext context,
} }
if (!ob::openbox->bindings()->addButton(button, context, if (!ob::openbox->bindings()->addButton(button, context,
action, func)) { action, func)) {
PyErr_SetString(PyExc_RuntimeError,"Unable to add binding."); PyErr_SetString(PyExc_RuntimeError,"Unable to add binding.");
return NULL; return NULL;
} }
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }
PyObject *ebind(ob::EventAction action, PyObject *func) PyObject *ebind(ob::EventAction::EA action, PyObject *func)
{ {
if (!PyCallable_Check(func)) { if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "Invalid callback function."); PyErr_SetString(PyExc_TypeError, "Invalid callback function.");
@ -143,7 +142,7 @@ PyObject *kungrab()
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }
PyObject *kbind(PyObject *keylist, ob::KeyContext context, PyObject *func) PyObject *kbind(PyObject *keylist, ob::KeyContext::KC context, PyObject *func)
{ {
if (!PyCallable_Check(func)) { if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "Invalid callback function."); PyErr_SetString(PyExc_TypeError, "Invalid callback function.");
@ -233,4 +232,11 @@ PyObject *send_client_msg(Window target, Atom type, Window about,
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }
void execute(const std::string &bin, int screen)
{
if (screen >= ScreenCount(**otk::display))
screen = 0;
otk::bexec(bin, otk::display->screenInfo(screen)->displayString());
}
} }

View file

@ -24,53 +24,63 @@ namespace ob {
class Client; class Client;
enum MouseContext { struct MouseContext {
MC_Frame, enum MC {
MC_Titlebar, Frame,
MC_Handle, Titlebar,
MC_Window, Handle,
MC_MaximizeButton, Window,
MC_CloseButton, MaximizeButton,
MC_IconifyButton, CloseButton,
MC_AllDesktopsButton, IconifyButton,
MC_Grip, AllDesktopsButton,
MC_Root, Grip,
MC_MenuItem, Root,
NUM_MOUSE_CONTEXT MenuItem,
NUM_MOUSE_CONTEXT
};
}; };
enum MouseAction { struct MouseAction {
MousePress, enum MA {
MouseClick, Press,
MouseDoubleClick, Click,
MouseMotion, DoubleClick,
NUM_MOUSE_ACTION Motion,
NUM_MOUSE_ACTION
};
}; };
enum KeyContext { struct KeyContext {
KC_Menu, enum KC {
KC_All, Menu,
NUM_KEY_CONTEXT All,
NUM_KEY_CONTEXT
};
}; };
enum KeyAction { struct KeyAction {
EventKeyPress, enum KA {
EventKeyRelease, Press,
NUM_KEY_ACTION Release,
NUM_KEY_ACTION
};
}; };
enum EventAction { struct EventAction {
EventEnterWindow, enum EA {
EventLeaveWindow, EnterWindow,
EventPlaceWindow, LeaveWindow,
EventNewWindow, PlaceWindow,
EventCloseWindow, NewWindow,
EventStartup, CloseWindow,
EventShutdown, Startup,
EventFocus, Shutdown,
EventBell, Focus,
EventUrgentWindow, Bell,
NUM_EVENTS UrgentWindow,
NUM_EVENTS
};
}; };
class MouseData { class MouseData {
@ -80,8 +90,8 @@ public:
Time time; Time time;
unsigned int state; unsigned int state;
unsigned int button; unsigned int button;
MouseContext context; MouseContext::MC context;
MouseAction action; MouseAction::MA action;
int xroot; int xroot;
int yroot; int yroot;
int pressx; int pressx;
@ -92,9 +102,9 @@ public:
int press_clientheight; int press_clientheight;
MouseData(int screen, Client *client, Time time, unsigned int state, MouseData(int screen, Client *client, Time time, unsigned int state,
unsigned int button, MouseContext context, MouseAction action, unsigned int button, MouseContext::MC context,
int xroot, int yroot, const otk::Point &initpos, MouseAction::MA action, int xroot, int yroot,
const otk::Rect &initarea) { const otk::Point &initpos, const otk::Rect &initarea) {
this->screen = screen; this->screen = screen;
this->client = client; this->client = client;
this->time = time; this->time = time;
@ -112,7 +122,8 @@ public:
this->press_clientheight = initarea.height(); this->press_clientheight = initarea.height();
} }
MouseData(int screen, Client *client, Time time, unsigned int state, MouseData(int screen, Client *client, Time time, unsigned int state,
unsigned int button, MouseContext context, MouseAction action) { unsigned int button, MouseContext::MC context,
MouseAction::MA action) {
this->screen = screen; this->screen = screen;
this->client = client; this->client = client;
this->time = time; this->time = time;
@ -136,9 +147,9 @@ public:
int screen; int screen;
Client *client; Client *client;
unsigned int state; unsigned int state;
EventAction action; EventAction::EA action;
EventData(int screen, Client *client, EventAction action, EventData(int screen, Client *client, EventAction::EA action,
unsigned int state) { unsigned int state) {
this->screen = screen; this->screen = screen;
this->client = client; this->client = client;
@ -154,10 +165,10 @@ public:
Time time; Time time;
unsigned int state; unsigned int state;
char *key; char *key;
KeyAction action; KeyAction::KA action;
KeyData(int screen, Client *client, Time time, unsigned int state, KeyData(int screen, Client *client, Time time, unsigned int state,
unsigned int key, KeyAction action) { unsigned int key, KeyAction::KA action) {
this->screen = screen; this->screen = screen;
this->client = client; this->client = client;
this->time = time; this->time = time;
@ -187,21 +198,25 @@ void python_callback(PyObject *func, KeyData *data);
#endif // SWIG #endif // SWIG
PyObject *mbind(const std::string &button, ob::MouseContext context, PyObject *mbind(const std::string &button, ob::MouseContext::MC context,
ob::MouseAction action, PyObject *func); ob::MouseAction::MA action, PyObject *func);
PyObject *kbind(PyObject *keylist, ob::KeyContext context, PyObject *func); PyObject *kbind(PyObject *keylist, ob::KeyContext::KC context, PyObject *func);
PyObject *kgrab(int screen, PyObject *func); PyObject *kgrab(int screen, PyObject *func);
PyObject *kungrab(); PyObject *kungrab();
PyObject *ebind(ob::EventAction action, PyObject *func); PyObject *ebind(ob::EventAction::EA action, PyObject *func);
void set_reset_key(const std::string &key); void set_reset_key(const std::string &key);
PyObject *send_client_msg(Window target, Atom type, Window about, PyObject *send_client_msg(Window target, Atom type, Window about,
long data, long data1 = 0, long data2 = 0, long data, long data1 = 0, long data2 = 0,
long data3 = 0, long data4 = 0); long data3 = 0, long data4 = 0);
void execute(const std::string &bin, int screen=0);
} }

View file

@ -134,7 +134,7 @@ Screen::Screen(int screen)
openbox->registerHandler(_info->rootWindow(), this); openbox->registerHandler(_info->rootWindow(), this);
// call the python Startup callbacks // call the python Startup callbacks
EventData data(_number, 0, EventShutdown, 0); EventData data(_number, 0, EventAction::Shutdown, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
} }
@ -150,7 +150,7 @@ Screen::~Screen()
unmanageWindow(clients.front()); unmanageWindow(clients.front());
// call the python Shutdown callbacks // call the python Shutdown callbacks
EventData data(_number, 0, EventShutdown, 0); EventData data(_number, 0, EventAction::Shutdown, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
XDestroyWindow(**otk::display, _focuswindow); XDestroyWindow(**otk::display, _focuswindow);
@ -498,7 +498,7 @@ void Screen::manageWindow(Window window)
client->positionRequested())) { client->positionRequested())) {
// position the window intelligenty .. hopefully :) // position the window intelligenty .. hopefully :)
// call the python PLACEWINDOW binding // call the python PLACEWINDOW binding
EventData data(_number, client, EventPlaceWindow, 0); EventData data(_number, client, EventAction::PlaceWindow, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
} }
@ -523,7 +523,7 @@ void Screen::manageWindow(Window window)
openbox->bindings()->grabButtons(true, client); openbox->bindings()->grabButtons(true, client);
// call the python NEWWINDOW binding // call the python NEWWINDOW binding
EventData data(_number, client, EventNewWindow, 0); EventData data(_number, client, EventAction::NewWindow, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
#ifdef DEBUG #ifdef DEBUG
@ -538,7 +538,7 @@ void Screen::unmanageWindow(Client *client)
Frame *frame = client->frame; Frame *frame = client->frame;
// call the python CLOSEWINDOW binding // call the python CLOSEWINDOW binding
EventData data(_number, client, EventCloseWindow, 0); EventData data(_number, client, EventAction::CloseWindow, 0);
openbox->bindings()->fireEvent(&data); openbox->bindings()->fireEvent(&data);
openbox->bindings()->grabButtons(false, client); openbox->bindings()->grabButtons(false, client);

View file

@ -32,34 +32,34 @@ public:
inline WidgetType type() const { return _type; } inline WidgetType type() const { return _type; }
inline MouseContext mcontext() const { inline MouseContext::MC mcontext() const {
switch (_type) { switch (_type) {
case Type_Frame: case Type_Frame:
return MC_Frame; return MouseContext::Frame;
case Type_Titlebar: case Type_Titlebar:
return MC_Titlebar; return MouseContext::Titlebar;
case Type_Handle: case Type_Handle:
return MC_Handle; return MouseContext::Handle;
case Type_Plate: case Type_Plate:
return MC_Window; return MouseContext::Window;
case Type_Label: case Type_Label:
return MC_Titlebar; return MouseContext::Titlebar;
case Type_MaximizeButton: case Type_MaximizeButton:
return MC_MaximizeButton; return MouseContext::MaximizeButton;
case Type_CloseButton: case Type_CloseButton:
return MC_CloseButton; return MouseContext::CloseButton;
case Type_IconifyButton: case Type_IconifyButton:
return MC_IconifyButton; return MouseContext::IconifyButton;
case Type_AllDesktopsButton: case Type_AllDesktopsButton:
return MC_AllDesktopsButton; return MouseContext::AllDesktopsButton;
case Type_LeftGrip: case Type_LeftGrip:
return MC_Grip; return MouseContext::Grip;
case Type_RightGrip: case Type_RightGrip:
return MC_Grip; return MouseContext::Grip;
case Type_Client: case Type_Client:
return MC_Window; return MouseContext::Window;
case Type_Root: case Type_Root:
return MC_Root; return MouseContext::Root;
default: default:
assert(false); // unhandled type assert(false); // unhandled type
} }