#!/usr/bin/python # $Id: plpwm.py,v 1.16 2002/02/18 04:27:48 mwm Exp $ # # plpwm.py -- Exemple PLWM window manager configuration with panes. # # Copyright (C) 2001 Mike Meyer # # 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """plpwm.py - Pointer Less Paned Window Manager Example PLWM window manager configuration with panes.""" import sys, os ###SETUP PATH sys.path[1:1] = [os.path.join(sys.path[0], '..')] import plwm.xlibpath ###END SETUP PATH from Xlib import X, XK from plwm import wmanager, keys, inspect, \ border, color, font, menu, panes, cfilter, input, message border.BorderClient.border_default_width = 5 class MyMenuHandler(menu.MenuCharHandler): Any_Escape = C_g = menu.MenuKeyHandler._abort Any_Return = menu.MenuKeyHandler._do Any_space = Any_Down = C_n = menu.MenuKeyHandler._down Any_BackSpace = Any_Up = C_p = menu.MenuKeyHandler._up class MyEditHandler(input.InputKeyHandler): Any_Escape = C_g = input.InputKeyHandler._abort Any_Return = input.InputKeyHandler._done Any_BackSpace = C_h = input.InputKeyHandler._delback C_d = input.InputKeyHandler._delforw C_b = input.InputKeyHandler._back C_f = input.InputKeyHandler._forw C_k = input.InputKeyHandler._deltoend C_a = input.InputKeyHandler._begin C_e = input.InputKeyHandler._end C_y = input.InputKeyHandler._paste class MyClient(wmanager.Client, border.BorderClient, panes.panesClient): "Put the clients in panes, with a border." class MyScreen(wmanager.Screen, color.Color, message.screenMessage, panes.panesScreen, menu.screenMenu): "And panes on the screen, and I'm going to want some menus." menu_handler = MyMenuHandler allow_raise_requests = 0 class WMConfig: def __wm_init__(my): "install the panes key map" PaneKeys(my) class PLPWM(wmanager.WindowManager, font.Font, panes.panesManager, inspect.InspectServer, WMConfig): "Set up my window manager." client_class = MyClient screen_class = MyScreen class PaneKeys(keys.KeyHandler): "The pane control keys." # Commands for navigating and manipulating panes def M1_Escape(my, event): my.wm.quit() def C_0(my, event): "Go to the pane numbered by the keycode." my.wm.panes_goto(my.wm.display.keycode_to_keysym(event.detail, 0) - XK.XK_0) C_1 = C_2 = C_3 = C_4 = C_5 = C_6 = C_7 = C_8 = C_9 = C_0 def M1_Tab(my, event): my.wm.panes_next() def S_M1_Tab(my, event): my.wm.panes_prev() def M1_1(my, event): my.wm.panes_list[my.wm.panes_current].maximize() def M1_2(my, event): split_pane(my.wm.display.keycode_to_keysym(event.detail, 0) - XK.XK_0, my.wm.panes_list[my.wm.panes_current].horizontal_split) M1_3 = M1_4 = M1_5 = M1_6 = M1_7 = M1_8 = M1_9 = M1_2 def S_M1_2(my, event): split_pane(my.wm.display.keycode_to_keysym(event.detail, 0) - XK.XK_0, my.wm.panes_list[my.wm.panes_current].vertical_split) S_M1_3 = S_M1_4 = S_M1_5 = S_M1_6 = S_M1_7 = S_M1_8 = S_M1_9 = S_M1_2 # Keystrokes for launching applications def M1_exclam(my, event): runcommand(my.wm.panes_list[my.wm.panes_current]) def M1_m(my, event): appmenu(my.wm.panes_list[my.wm.panes_current], {'words': 'applix -wp', 'sql': 'applix -db', 'sheet': 'applix -ss', 'fxtv': 'fxtv', 'w3m': 'w3m', 'skipstone': 'skipstone'}) def M1_b(my, event): getapp(my.wm.panes_list[my.wm.panes_current], "w3m") def M1_c(my, event): my.wm.system("xterm -ls &") def M1_e(my, event): my.wm.panes_goto(0) # always run emacs in pane 0. getapp(my.wm.panes_list[my.wm.panes_current], "emacs", "xemacs") def M1_i(my, event): getapp(my.wm.panes_list[my.wm.panes_current], "/home/mwm/axhome/axMail/Inbox.sp", "applix -inbox") def M1_j(my, event): getapp(my.wm.panes_list[my.wm.panes_current], "J-Pilot", "jpilot") def M1_s(my, event): getapp(my.wm.panes_list[my.wm.panes_current], "SkipStone", "skipstone") # Keystrokes for window manager operations def M1_quoteright(my, event): pullwindow(my.wm.panes_list[my.wm.panes_current]) def M1_quotedbl(my, event): gotowindow(my.wm.panes_list[my.wm.panes_current]) def M1_Return(my, event): my.wm.panes_list[my.wm.panes_current].next_window() def S_M1_Return(my, event): my.wm.panes_list[my.wm.panes_current].prev_window() def M1_k(my, event): my.wm.panes_list[my.wm.panes_current].window.delete(1) def S_M1_k(my, event): my.wm.panes_list[my.wm.panes_current].window.destroy() def M1_r(my, event): my.wm.panes_list[my.wm.panes_current].force_window() def M1_u(my, event): windowmenu(my.wm.panes_list[my.wm.panes_current], lambda w: not (w.panes_pane and w.panes_pane.window == w)) def M1_x(my, event): ExtendedPaneKeys(my.wm, event.time) # Aliases for some of the keystrokes M1_space = M1_Return S_M1_space = S_M1_Return class ExtendedPaneKeys(keys.KeyGrabKeyboard): "Extended command, with a timeout." def M1_b(my, event): windowmenu(my.wm.panes_list[my.wm.panes_current]) my._cleanup() def M1_f(my, event): width, height = my.wm.current_screen.message_make("Current pane %d" \ % my.wm.panes_current) pane = my.wm.panes_list[my.wm.panes_current] my.wm.current_screen.message_display((pane.width - width) / 2 + pane.x, (pane.height - height) / 2 + pane.y) my._cleanup() def M1_i(my, event): my.wm.inspect_enable() my.wm.system('xterm -title Inspector -e inspect_plwm &') my._cleanup() def M1_m(my, event): appmenu(my.wm.panes_list[my.wm.panes_current], {'mixer': 'xgmixer', 'console': 'xconsole -daemon', 'gkrellm': 'gkrellm'}) my._cleanup() def M1_p(my, event): panesmenu(my.wm.current_screen) my._cleanup() def M1_r(my, event): restore(my.wm) my._cleanup() def M1_s(my, event): my.wm.panes_save() my._cleanup() def M1_u(my, event): windowmenu(my.wm.panes_list[my.wm.panes_current], cfilter.iconified) my._cleanup() def M1_w(my, event): pane = my.wm.panes_list[my.wm.panes_current] windowmenu(pane, panes.panefilter(pane)) my._cleanup() def M1_x(my, event): my.wm.panes_list[my.wm.panes_current].iconify_window() my._cleanup() Any_g = Any_Escape = keys.KeyGrabKeyboard._timeout class appmenu: "Creates a menu of applications to run in a pane." def __init__(my, pane, apps): "Create and run the applications menu from the keys." labels = apps.keys() labels.sort() width, height = pane.screen.menu_make(labels) my.system = pane.screen.system my.apps = apps pane.screen.menu_run((pane.width - width) / 2 + pane.x, (pane.height - height) / 2 + pane.y, my) def __call__(my, choice): "Call the system function on the value of the given choice." my.system(my.apps[choice] + " &") class windowmenu: "Create a menu of windows to add to a pane." def __init__(my, pane, filter = cfilter.true, list = None): labels = [] clients = {} i = 'a' for c in list or pane.screen.query_clients(filter, 1): l = "%c: %s" % (i, c.get_title()) labels.append(l) clients[l] = c i = chr(ord(i) + 1) if labels: width, height = pane.screen.menu_make(labels, align = 'left') my.add = pane.add_window my.clients = clients pane.screen.menu_run((pane.width - width) / 2 + pane.x, (pane.height - height) / 2 + pane.y, my) else: width, height = pane.screen.message_make("No windows") pane.screen.message_display((pane.width - width) / 2 + pane.x, (pane.height - height) / 2 + pane.y) def __call__(my, choice): "Add the selected window to the pane." my.add(my.clients[choice]) class panesmenu: "Create a menu of all the panes." def __init__(my, screen): wm = screen.wm labels = [] panes = {} for i in range(len(wm.panes_list)): w = wm.panes_list[i].window if w: l = "%d: %s" % (i, w.get_title()) else: l = "%d: " % i labels.append(l) panes[l] = i width, height = screen.menu_make(labels, align = 'left') my.goto = wm.panes_goto my.panes = panes screen.menu_run((screen.root_width - width) / 2, (screen.root_height - height) / 2, my) def __call__(my, choice): "Activate the selected pane." my.goto(my.panes[choice]) class runcommand: "Read a string from the user, and run it." def __init__(my, pane): my.system = pane.screen.system window = input.inputWindow("! ", pane.screen, length = 50) window.read(my, MyEditHandler, pane.x, pane.y) def __call__(my, string): my.system(string + " &") class pullwindow: "Read a window's name, and pull it to the current pane." def __init__(my, pane): my.pane = pane window = input.inputWindow("pull ", pane.screen) window.read(my, MyEditHandler, pane.x, pane.y) def __call__(my, name): clients = my.pane.screen.query_clients(cfilter.re_title(name + ".*"), 1) if len(clients) == 1: my.pane.add_window(clients[0]) elif clients: windowmenu(my.pane, list = clients) else: width, height = my.pane.screen.message_make("No windows") my.pane.screen.message_display(my.pane.x, my.pane.y) class gotowindow: "Emulate the rp 'goto' command." def __init__(my, pane): my.pane = pane window = input.inputWindow("goto ", pane.screen) window.read(my, MyEditHandler) def __call__(my, name): clients = my.pane.screen.query_clients(cfilter.re_title(name + ".*"), 1) if clients: window = clients[0] if window.panes_pane.window and window.panes_pane.window == window: my.pane.wm.panes_activate(window.panes_pane) else: my.pane.add_window(window) else: width, height = my.pane.screen.message_make("No windows") my.pane.screen.message_display(0, 0) def getapp(pane, name, command = None): "Find a window starting with name, and run command if it doesn't exist." clients = pane.screen.query_clients(cfilter.re_title(name + ".*"), 1) if len(clients) > 1: windowmenu(pane, list = clients) elif clients: pane.add_window(clients[0]) else: pane.screen.system((command or name) + " &") def restore(wm): "Build my standard work environment." pane = wm.panes_list[wm.panes_current] pane.maximize() # Disconnect all windows from panes to avoid displaying everything # that's about to happen. wm.panes_restore() will put things back. for c in wm.query_clients(): c.panes_pane = None pane.window = None pane.vertical_split() wm.panes_number(0) wm.panes_goto(1) pane.horizontal_split(.0625) pane.vertical_split(.75) wm.panes_number(1) pane = wm.panes_list[1] pane.horizontal_split(94. / 225.) wm.panes_number(3) pane.horizontal_split() wm.panes_number(2) pane = wm.panes_list[4] pane.horizontal_split(16. / 45.) pane.horizontal_split(24. / 29.) wm.panes_goto(4) wm.panes_restore() def split_pane(count, splitter): "Split current pane into 2-9 equal-sized panes." while count > 1: splitter(1. / count) count -= 1 if __name__ == '__main__': wmanager.main(PLPWM)