1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# -*- python -*-
'''
xpybar – xmobar replacement written in python
Copyright © 2014, 2015, 2016, 2017, 2018 Mattias Andrée (maandree@kth.se)
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 <http://www.gnu.org/licenses/>.
'''
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]
|