# -*- python -*- ''' xpybar – xmobar replacement written in python Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Mattias Andrée (m@maandreese) 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 3 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, see . ''' class Menu: ''' Dropdown menu Instances of this class is compatible with `Bar` You should extend the global function `stop` to unmap any menu that is still open at the time that function is called @variable window The X window @variable gc The window's graphics context @variable cmap The window's colour map @variable width:int The menu's pixel width @variable height:int The output's pixel height @variable left:int The output's left position @variable top:int The output's top position @variable ypos:int The position of the menu in relation to either the top or bottom edge of the output @variable panel_height:int The menu's height, note that the name is `panel_height` for compatibility with `Bar` @variable at_top:bool Whether the menu is to be positioned relative the top of the output, otherwise to the bottom @variable background The default background @variable foreground The default foreground @variable font The default font @variable font_metrics The default font's metrics @variable font_height:int The height of the default font @variable font_width:int The width of an 'X' with the default font @variable palette A 16-array of standard colours @variable cmap_cache Custom colour map cache ''' methods_set = False ''' :bool Indicates whether a constructor has set methods common with `Bar` ''' def __init__(self, output, width, height, xpos, ypos, left, top, font = None, background = None, foreground = None, event_mask = None, override_redirect = True): ''' Constructor @param output:int The index of the output within the screen as printed by xrandr, except primary is first @param width:int The width of the menu @param height:int The height of the menu @param xpos:int The position of the menu in relation the either the left or right edge of the output @param ypos:int The position of the menu in relation the either the top or bottom edge of the output @param left:int Whether the menu is positioned relative to the left of the output, otherwise to the right @param top:int Whether the menu is positioned relative to the top of the output, otherwise to the bottom @param font:str? The default font, `None` for the default @param background:(red:int, green:int, blue:int)? The default background, `None` for the default @param foreground:(red:int, green:int, blue:int)? The default foreground, `None` for the default @param event:int? Mask of events that should be caught, `None` for the default @param override_redirect:bool Whether override_redirect should be set ''' import os import Xlib.display, Xlib.Xatom, Xlib.ext.randr, Xlib.X if not Menu.methods_set: Menu.map = Bar.map Menu.unmap = Bar.unmap Menu.text_width = Bar.text_width Menu.draw_text = Bar.draw_text Menu.draw_coloured_text = Bar.draw_coloured_text Menu.draw_coloured_splitted_text = Bar.draw_coloured_splitted_text Menu.create_colour = Bar.create_colour Menu.create_font = Bar.create_font Menu.change_colour = Bar.change_colour Menu.change_font = Bar.change_font Menu.clear_rectangle = Bar.clear_rectangle Menu.clear = Bar.clear Menu.invalidate = Bar.invalidate Menu.coloured_length = Bar.coloured_length Menu.methods_set = True if event_mask is None: event_mask = ( Xlib.X.StructureNotifyMask | Xlib.X.ButtonPressMask | Xlib.X.ButtonReleaseMask | Xlib.X.ExposureMask | Xlib.X.KeyPress | Xlib.X.KeyRelease | Xlib.X.MotionNotify | Xlib.X.EnterNotify | Xlib.X.LeaveNotify ) if font is None: font = FONT if background is None: background = BACKGROUND if foreground is None: foreground = FOREGROUND [self.width, self.height, self.left, self.top] = outputs[output][:4] [self.ypos, self.panel_height, self.at_top] = [ypos, height, top] self.left += xpos if left else (self.width - xpos - width) self.top += ypos if top else (self.height - ypos - height) self.width = width self.window = screen.root.create_window(self.left, self.top, self.width, self.panel_height, 0, Xlib.X.CopyFromParent, Xlib.X.InputOutput, Xlib.X.CopyFromParent, event_mask = event_mask, colormap = Xlib.X.CopyFromParent, override_redirect = override_redirect) self.window.set_wm_name('xpybar') self.window.set_wm_icon_name('xpybar') self.window.set_wm_class('menu', 'xpybar') self.window.set_wm_client_machine(os.uname().nodename) _CARD = display.intern_atom("CARDINAL") _DESKTOP = display.intern_atom("_NET_WM_DESKTOP") _PID = display.intern_atom("_NET_WM_PID") self.window.change_property(_DESKTOP, _CARD, 32, [0xFFFFFFFF]) self.window.change_property(_PID, _CARD, 32, [os.getpid()]) _ATOM = display.intern_atom("ATOM") _TYPE = display.intern_atom("_NET_WM_WINDOW_TYPE") _NORMAL = display.intern_atom("_NET_WM_WINDOW_TYPE_NORMAL") self.window.change_property(_TYPE, _ATOM, 32, [_NORMAL]) self.gc = self.window.create_gc() self.cmap = self.window.get_attributes().colormap self.cmap_cache = {} self.background = self.create_colour(*background) self.foreground = self.create_colour(*foreground) (self.font, self.font_metrics, self.font_height) = self.create_font(font) self.font_width = self.text_width('X') self.palette = [0x000000, 0xCD656C, 0x32A679, 0xCCAD47, 0x2495BE, 0xA46EB0, 0x00A09F, 0xD8D8D8] self.palette += [0x555555, 0xEB5E6A, 0x0EC287, 0xF2CA38, 0x00ACE0, 0xC473D1, 0x00C3C7, 0xEEEEEE] self.palette = [((p >> 16) & 255, (p >> 8) & 255, p & 255) for p in self.palette] self.palette = [self.create_colour(*p) for p in self.palette]