style: spaces -> tabs
This commit is contained in:
		
							parent
							
								
									7b3700e730
								
							
						
					
					
						commit
						0f81338bb6
					
				
							
								
								
									
										36
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								meson.build
									
									
									
									
									
								
							| @ -1,9 +1,9 @@ | |||||||
| project('somebar', ['c', 'cpp'], | project('somebar', ['c', 'cpp'], | ||||||
|   version: '0.1.0', | 	version: '0.1.0', | ||||||
|   default_options: [ | 	default_options: [ | ||||||
|     'cpp_std=c++17', | 	    'cpp_std=c++17', | ||||||
|     'cpp_args=-Wno-parentheses', | 	    'cpp_args=-Wno-parentheses', | ||||||
|   ]) | 	]) | ||||||
| 
 | 
 | ||||||
| wayland_dep = dependency('wayland-client') | wayland_dep = dependency('wayland-client') | ||||||
| wayland_cursor_dep = dependency('wayland-cursor') | wayland_cursor_dep = dependency('wayland-cursor') | ||||||
| @ -14,16 +14,16 @@ pangocairo_dep = dependency('pangocairo') | |||||||
| subdir('protocols') | subdir('protocols') | ||||||
| 
 | 
 | ||||||
| executable('somebar', | executable('somebar', | ||||||
|   'src/main.cpp', | 	'src/main.cpp', | ||||||
|   'src/shm_buffer.cpp', | 	'src/shm_buffer.cpp', | ||||||
|   'src/bar.cpp', | 	'src/bar.cpp', | ||||||
|   wayland_sources, | 	wayland_sources, | ||||||
|   dependencies: [ | 	dependencies: [ | ||||||
|     wayland_dep, | 	    wayland_dep, | ||||||
|     wayland_cursor_dep, | 	    wayland_cursor_dep, | ||||||
|     cairo_dep, | 	    cairo_dep, | ||||||
|     pango_dep, | 	    pango_dep, | ||||||
|     pangocairo_dep, | 	    pangocairo_dep, | ||||||
|   ], | 	], | ||||||
|   install: true, | 	install: true, | ||||||
|   cpp_args: '-DSOMEBAR_VERSION="@0@"'.format(meson.project_version())) | 	cpp_args: '-DSOMEBAR_VERSION="@0@"'.format(meson.project_version())) | ||||||
|  | |||||||
| @ -3,21 +3,21 @@ wayland_scanner = find_program('wayland-scanner') | |||||||
| wayland_protos_dep = dependency('wayland-protocols') | wayland_protos_dep = dependency('wayland-protocols') | ||||||
| wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') | wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') | ||||||
| wayland_scanner_code = generator( | wayland_scanner_code = generator( | ||||||
|   wayland_scanner, | 	wayland_scanner, | ||||||
|   output: '@BASENAME@-protocol.c', | 	output: '@BASENAME@-protocol.c', | ||||||
|   arguments: ['private-code', '@INPUT@', '@OUTPUT@']) | 	arguments: ['private-code', '@INPUT@', '@OUTPUT@']) | ||||||
| wayland_scanner_client = generator( | wayland_scanner_client = generator( | ||||||
|   wayland_scanner, | 	wayland_scanner, | ||||||
|   output: '@BASENAME@-client-protocol.h', | 	output: '@BASENAME@-client-protocol.h', | ||||||
|   arguments: ['client-header', '@INPUT@', '@OUTPUT@']) | 	arguments: ['client-header', '@INPUT@', '@OUTPUT@']) | ||||||
| 
 | 
 | ||||||
| wayland_xmls = [ | wayland_xmls = [ | ||||||
|   wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', | 	wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', | ||||||
|   wl_protocol_dir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', | 	wl_protocol_dir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', | ||||||
|   'wlr-layer-shell-unstable-v1.xml', | 	'wlr-layer-shell-unstable-v1.xml', | ||||||
|   'net-tapesoftware-dwl-wm-unstable-v1.xml', | 	'net-tapesoftware-dwl-wm-unstable-v1.xml', | ||||||
| ] | ] | ||||||
| wayland_sources = [ | wayland_sources = [ | ||||||
|   wayland_scanner_code.process(wayland_xmls), | 	wayland_scanner_code.process(wayland_xmls), | ||||||
|   wayland_scanner_client.process(wayland_xmls), | 	wayland_scanner_client.process(wayland_xmls), | ||||||
| ] | ] | ||||||
|  | |||||||
| @ -1,164 +1,164 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <protocol name="net_tapesoftware_dwl_wm_unstable_v1"> | <protocol name="net_tapesoftware_dwl_wm_unstable_v1"> | ||||||
|     <copyright> | 	<copyright> | ||||||
|         Copyright (c) 2021 Raphael Robatsch | 		Copyright (c) 2021 Raphael Robatsch | ||||||
| 
 | 
 | ||||||
|         Permission is hereby granted, free of charge, to any person obtaining a | 		Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|         copy of this software and associated documentation files (the | 		copy of this software and associated documentation files (the | ||||||
|         "Software"), to deal in the Software without restriction, including | 		"Software"), to deal in the Software without restriction, including | ||||||
|         without limitation the rights to use, copy, modify, merge, publish, | 		without limitation the rights to use, copy, modify, merge, publish, | ||||||
|         distribute, sublicense, and/or sell copies of the Software, and to | 		distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|         permit persons to whom the Software is furnished to do so, subject to | 		permit persons to whom the Software is furnished to do so, subject to | ||||||
|         the following conditions: | 		the following conditions: | ||||||
| 
 | 
 | ||||||
|         The above copyright notice and this permission notice (including the | 		The above copyright notice and this permission notice (including the | ||||||
|         next paragraph) shall be included in all copies or substantial portions | 		next paragraph) shall be included in all copies or substantial portions | ||||||
|         of the Software. | 		of the Software. | ||||||
| 
 | 
 | ||||||
|         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||||
|         OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 		OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|         MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | 		MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||||
|         IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | 		IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||||
|         CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | 		CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||||
|         TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | 		TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||||
|         SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 		SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|     </copyright> | 	</copyright> | ||||||
| 
 | 
 | ||||||
|     <interface name="znet_tapesoftware_dwl_wm_v1" version="1"> | 	<interface name="znet_tapesoftware_dwl_wm_v1" version="1"> | ||||||
|         <description summary="control the dwl state"> | 		<description summary="control the dwl state"> | ||||||
|             This interface is exposed as a global in the wl_registry. | 			This interface is exposed as a global in the wl_registry. | ||||||
| 
 | 
 | ||||||
|             Clients can use this protocol to receive updates of the window manager | 			Clients can use this protocol to receive updates of the window manager | ||||||
|             state (active tags, active layout, and focused window). | 			state (active tags, active layout, and focused window). | ||||||
|             Clients can also control this state. | 			Clients can also control this state. | ||||||
| 
 | 
 | ||||||
|             After binding, the client will receive the available tags and layouts | 			After binding, the client will receive the available tags and layouts | ||||||
|             with the 'tag' and 'layout' events. These can be used in subsequent | 			with the 'tag' and 'layout' events. These can be used in subsequent | ||||||
|             dwl_wm_monitor_v1.set_tags/set_layout requests, and to interpret the | 			dwl_wm_monitor_v1.set_tags/set_layout requests, and to interpret the | ||||||
|             dwl_wm_monitor_v1.layout/tag events. | 			dwl_wm_monitor_v1.layout/tag events. | ||||||
|         </description> | 		</description> | ||||||
| 
 | 
 | ||||||
|         <request name="release" type="destructor"> | 		<request name="release" type="destructor"> | ||||||
|             <description summary="release dwl_wm"> | 			<description summary="release dwl_wm"> | ||||||
|                 This request indicates that the client will not use the dwl_wm | 				This request indicates that the client will not use the dwl_wm | ||||||
|                 object any more. Objects that have been created through this instance | 				object any more. Objects that have been created through this instance | ||||||
|                 are not affected. | 				are not affected. | ||||||
|             </description> | 			</description> | ||||||
|         </request> | 		</request> | ||||||
| 
 | 
 | ||||||
|         <request name="get_monitor"> | 		<request name="get_monitor"> | ||||||
|             <description summary="gets a dwl monitor from an output"> | 			<description summary="gets a dwl monitor from an output"> | ||||||
|                 Gets a dwl monitor for the specified output. The window manager | 				Gets a dwl monitor for the specified output. The window manager | ||||||
|                 state on the output can be controlled using the monitor. | 				state on the output can be controlled using the monitor. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="id" type="new_id" interface="znet_tapesoftware_dwl_wm_monitor_v1" /> | 			<arg name="id" type="new_id" interface="znet_tapesoftware_dwl_wm_monitor_v1" /> | ||||||
|             <arg name="output" type="object" interface="wl_output" /> | 			<arg name="output" type="object" interface="wl_output" /> | ||||||
|         </request> | 		</request> | ||||||
| 
 | 
 | ||||||
|         <event name="tag"> | 		<event name="tag"> | ||||||
|             <description summary="announces the presence of a tag"> | 			<description summary="announces the presence of a tag"> | ||||||
|                 This event is sent immediately after binding. | 				This event is sent immediately after binding. | ||||||
|                 A roundtrip after binding guarantees that the client has received all tags. | 				A roundtrip after binding guarantees that the client has received all tags. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="name" type="string"/> | 			<arg name="name" type="string"/> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <event name="layout"> | 		<event name="layout"> | ||||||
|             <description summary="announces the presence of a layout"> | 			<description summary="announces the presence of a layout"> | ||||||
|                 This event is sent immediately after binding. | 				This event is sent immediately after binding. | ||||||
|                 A roundtrip after binding guarantees that the client has received all layouts. | 				A roundtrip after binding guarantees that the client has received all layouts. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="name" type="string"/> | 			<arg name="name" type="string"/> | ||||||
|         </event> | 		</event> | ||||||
|     </interface> | 	</interface> | ||||||
| 
 | 
 | ||||||
|     <interface name="znet_tapesoftware_dwl_wm_monitor_v1" version="1"> | 	<interface name="znet_tapesoftware_dwl_wm_monitor_v1" version="1"> | ||||||
|         <description summary="control one monitor"> | 		<description summary="control one monitor"> | ||||||
|             Observes and controls one monitor. | 			Observes and controls one monitor. | ||||||
| 
 | 
 | ||||||
|             Events are double-buffered: Clients should cache all events and only | 			Events are double-buffered: Clients should cache all events and only | ||||||
|             redraw themselves once the 'frame' event is sent. | 			redraw themselves once the 'frame' event is sent. | ||||||
| 
 | 
 | ||||||
|             Requests are not double-buffered: The compositor will update itself | 			Requests are not double-buffered: The compositor will update itself | ||||||
|             immediately. | 			immediately. | ||||||
|         </description> | 		</description> | ||||||
| 
 | 
 | ||||||
|         <enum name="tag_state"> | 		<enum name="tag_state"> | ||||||
|             <entry name="none" value="0" summary="no state"/> | 			<entry name="none" value="0" summary="no state"/> | ||||||
|             <entry name="active" value="1" summary="tag is active"/> | 			<entry name="active" value="1" summary="tag is active"/> | ||||||
|             <entry name="urgent" value="2" summary="tag has at least one urgent client"/> | 			<entry name="urgent" value="2" summary="tag has at least one urgent client"/> | ||||||
|         </enum> | 		</enum> | ||||||
| 
 | 
 | ||||||
|         <request name="release" type="destructor"> | 		<request name="release" type="destructor"> | ||||||
|             <description summary="release dwl_monitor"> | 			<description summary="release dwl_monitor"> | ||||||
|                 This request indicates that the client is done with this dwl_monitor. | 				This request indicates that the client is done with this dwl_monitor. | ||||||
|                 All further requests are ignored. | 				All further requests are ignored. | ||||||
|             </description> | 			</description> | ||||||
|         </request> | 		</request> | ||||||
| 
 | 
 | ||||||
|         <event name="selected"> | 		<event name="selected"> | ||||||
|             <description summary="updates the selected state of the monitor"> | 			<description summary="updates the selected state of the monitor"> | ||||||
|                 If 'selected' is nonzero, this monitor is the currently selected one. | 				If 'selected' is nonzero, this monitor is the currently selected one. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="selected" type="uint"/> | 			<arg name="selected" type="uint"/> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <event name="tag"> | 		<event name="tag"> | ||||||
|             <description summary="updates the state of one tag"> | 			<description summary="updates the state of one tag"> | ||||||
|                 Announces the update of a tag. num_clients and focused_client can be | 				Announces the update of a tag. num_clients and focused_client can be | ||||||
|                 used to draw client indicators. | 				used to draw client indicators. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="tag" type="uint" summary="index of a tag received by the dwl_wm_v1.tag event." /> | 			<arg name="tag" type="uint" summary="index of a tag received by the dwl_wm_v1.tag event." /> | ||||||
|             <arg name="state" type="uint" enum="tag_state"/> | 			<arg name="state" type="uint" enum="tag_state"/> | ||||||
|             <arg name="num_clients" type="uint" summary="number of clients on this tag"/> | 			<arg name="num_clients" type="uint" summary="number of clients on this tag"/> | ||||||
|             <arg name="focused_client" type="int" summary="out of num_clients. -1 if there is no focused client"/> | 			<arg name="focused_client" type="int" summary="out of num_clients. -1 if there is no focused client"/> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <event name="layout"> | 		<event name="layout"> | ||||||
|             <description summary="updates the selected layout"> | 			<description summary="updates the selected layout"> | ||||||
|                 Announces the update of the selected layout. | 				Announces the update of the selected layout. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/> | 			<arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <event name="title"> | 		<event name="title"> | ||||||
|             <description summary="updates the focused client"> | 			<description summary="updates the focused client"> | ||||||
|                 Announces the update of the selected client. | 				Announces the update of the selected client. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="title" type="string"/> | 			<arg name="title" type="string"/> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <event name="frame"> | 		<event name="frame"> | ||||||
|             <description summary="end of status update sequence"> | 			<description summary="end of status update sequence"> | ||||||
|                 Sent after all other events belonging to the status update has been sent. | 				Sent after all other events belonging to the status update has been sent. | ||||||
|                 Clients should redraw themselves now. | 				Clients should redraw themselves now. | ||||||
|             </description> | 			</description> | ||||||
|         </event> | 		</event> | ||||||
| 
 | 
 | ||||||
|         <request name="set_tags"> | 		<request name="set_tags"> | ||||||
|             <description summary="sets the active tags on this monitor."> | 			<description summary="sets the active tags on this monitor."> | ||||||
|                 Changes are applied immediately. | 				Changes are applied immediately. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/> | 			<arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/> | ||||||
|             <arg name="toggle_tagset" type="uint"/> | 			<arg name="toggle_tagset" type="uint"/> | ||||||
|         </request> | 		</request> | ||||||
| 
 | 
 | ||||||
|         <request name="set_client_tags"> | 		<request name="set_client_tags"> | ||||||
|             <description summary="updates the tags of the focused client."> | 			<description summary="updates the tags of the focused client."> | ||||||
|                 tags are updated as follows: | 				tags are updated as follows: | ||||||
|                 new_tags = (current_tags AND and_tags) XOR xor_tags | 				new_tags = (current_tags AND and_tags) XOR xor_tags | ||||||
| 
 | 
 | ||||||
|                 Changes are applied immediately. | 				Changes are applied immediately. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="and_tags" type="uint"/> | 			<arg name="and_tags" type="uint"/> | ||||||
|             <arg name="xor_tags" type="uint"/> | 			<arg name="xor_tags" type="uint"/> | ||||||
|         </request> | 		</request> | ||||||
| 
 | 
 | ||||||
|         <request name="set_layout"> | 		<request name="set_layout"> | ||||||
|             <description summary="sets the active layout on this monitor."> | 			<description summary="sets the active layout on this monitor."> | ||||||
|                 Changes are applied immediately. | 				Changes are applied immediately. | ||||||
|             </description> | 			</description> | ||||||
|             <arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/> | 			<arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/> | ||||||
|         </request> | 		</request> | ||||||
|     </interface> | 	</interface> | ||||||
| </protocol> | </protocol> | ||||||
|  | |||||||
							
								
								
									
										316
									
								
								src/bar.cpp
									
									
									
									
									
								
							
							
						
						
									
										316
									
								
								src/bar.cpp
									
									
									
									
									
								
							| @ -11,44 +11,44 @@ | |||||||
| #include "pango/pango-layout.h" | #include "pango/pango-layout.h" | ||||||
| 
 | 
 | ||||||
| const zwlr_layer_surface_v1_listener Bar::_layerSurfaceListener = { | const zwlr_layer_surface_v1_listener Bar::_layerSurfaceListener = { | ||||||
|     [](void* owner, zwlr_layer_surface_v1*, uint32_t serial, uint32_t width, uint32_t height) | 	[](void* owner, zwlr_layer_surface_v1*, uint32_t serial, uint32_t width, uint32_t height) | ||||||
|     { | 	{ | ||||||
|         static_cast<Bar*>(owner)->layerSurfaceConfigure(serial, width, height); | 		static_cast<Bar*>(owner)->layerSurfaceConfigure(serial, width, height); | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| const wl_callback_listener Bar::_frameListener = { | const wl_callback_listener Bar::_frameListener = { | ||||||
|     [](void* owner, wl_callback* cb, uint32_t) | 	[](void* owner, wl_callback* cb, uint32_t) | ||||||
|     { | 	{ | ||||||
|         static_cast<Bar*>(owner)->render(); | 		static_cast<Bar*>(owner)->render(); | ||||||
|         wl_callback_destroy(cb); | 		wl_callback_destroy(cb); | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct Font { | struct Font { | ||||||
|     PangoFontDescription* description; | 	PangoFontDescription* description; | ||||||
|     int height {0}; | 	int height {0}; | ||||||
| }; | }; | ||||||
| static Font getFont() | static Font getFont() | ||||||
| { | { | ||||||
|     auto fontMap = pango_cairo_font_map_get_default(); | 	auto fontMap = pango_cairo_font_map_get_default(); | ||||||
|     if (!fontMap) die("pango_cairo_font_map_get_default"); | 	if (!fontMap) die("pango_cairo_font_map_get_default"); | ||||||
|     auto fontDesc = pango_font_description_from_string(font); | 	auto fontDesc = pango_font_description_from_string(font); | ||||||
|     if (!fontDesc) die("pango_font_description_from_string"); | 	if (!fontDesc) die("pango_font_description_from_string"); | ||||||
|     auto tempContext = pango_font_map_create_context(fontMap); | 	auto tempContext = pango_font_map_create_context(fontMap); | ||||||
|     if (!tempContext) die("pango_font_map_create_context"); | 	if (!tempContext) die("pango_font_map_create_context"); | ||||||
|     auto font = pango_font_map_load_font(fontMap, tempContext, fontDesc); | 	auto font = pango_font_map_load_font(fontMap, tempContext, fontDesc); | ||||||
|     if (!font) die("pango_font_map_load_font"); | 	if (!font) die("pango_font_map_load_font"); | ||||||
|     auto metrics = pango_font_get_metrics(font, pango_language_get_default()); | 	auto metrics = pango_font_get_metrics(font, pango_language_get_default()); | ||||||
|     if (!metrics) die("pango_font_get_metrics"); | 	if (!metrics) die("pango_font_get_metrics"); | ||||||
| 
 | 
 | ||||||
|     auto res = Font {}; | 	auto res = Font {}; | ||||||
|     res.description = fontDesc; | 	res.description = fontDesc; | ||||||
|     res.height = PANGO_PIXELS(pango_font_metrics_get_height(metrics)); | 	res.height = PANGO_PIXELS(pango_font_metrics_get_height(metrics)); | ||||||
| 
 | 
 | ||||||
|     pango_font_metrics_unref(metrics); | 	pango_font_metrics_unref(metrics); | ||||||
|     g_object_unref(font); | 	g_object_unref(font); | ||||||
|     g_object_unref(tempContext); | 	g_object_unref(tempContext); | ||||||
|     return res; | 	return res; | ||||||
| } | } | ||||||
| static Font barfont = getFont(); | static Font barfont = getFont(); | ||||||
| 
 | 
 | ||||||
| @ -56,27 +56,27 @@ BarComponent::BarComponent() { } | |||||||
| BarComponent::BarComponent(wl_unique_ptr<PangoLayout> layout) : pangoLayout {std::move(layout)} {} | BarComponent::BarComponent(wl_unique_ptr<PangoLayout> layout) : pangoLayout {std::move(layout)} {} | ||||||
| int BarComponent::width() const | int BarComponent::width() const | ||||||
| { | { | ||||||
|     int w, h; | 	int w, h; | ||||||
|     pango_layout_get_size(pangoLayout.get(), &w, &h); | 	pango_layout_get_size(pangoLayout.get(), &w, &h); | ||||||
|     return PANGO_PIXELS(w); | 	return PANGO_PIXELS(w); | ||||||
| } | } | ||||||
| void BarComponent::setText(const std::string& text) | void BarComponent::setText(const std::string& text) | ||||||
| { | { | ||||||
|     _text = std::make_unique<std::string>(text); | 	_text = std::make_unique<std::string>(text); | ||||||
|     pango_layout_set_text(pangoLayout.get(), _text->c_str(), _text->size()); | 	pango_layout_set_text(pangoLayout.get(), _text->c_str(), _text->size()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Bar::Bar(Monitor* mon) | Bar::Bar(Monitor* mon) | ||||||
| { | { | ||||||
|     _mon = mon; | 	_mon = mon; | ||||||
|     _pangoContext.reset(pango_font_map_create_context(pango_cairo_font_map_get_default())); | 	_pangoContext.reset(pango_font_map_create_context(pango_cairo_font_map_get_default())); | ||||||
|     if (!_pangoContext) die("pango_font_map_create_context"); | 	if (!_pangoContext) die("pango_font_map_create_context"); | ||||||
|     for (auto i=0u; i<tagNames.size(); i++) { | 	for (auto i=0u; i<tagNames.size(); i++) { | ||||||
|         _tags.push_back({ ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_NONE, 0, 0, createComponent(tagNames[i]) }); | 		_tags.push_back({ ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_NONE, 0, 0, createComponent(tagNames[i]) }); | ||||||
|     } | 	} | ||||||
|     _layoutCmp = createComponent(); | 	_layoutCmp = createComponent(); | ||||||
|     _titleCmp = createComponent(); | 	_titleCmp = createComponent(); | ||||||
|     _statusCmp = createComponent(); | 	_statusCmp = createComponent(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const wl_surface* Bar::surface() const { return _surface.get(); } | const wl_surface* Bar::surface() const { return _surface.get(); } | ||||||
| @ -84,35 +84,35 @@ bool Bar::visible() const { return _surface.get(); } | |||||||
| 
 | 
 | ||||||
| void Bar::show(wl_output* output) | void Bar::show(wl_output* output) | ||||||
| { | { | ||||||
|     if (visible()) return; | 	if (visible()) return; | ||||||
|     _surface.reset(wl_compositor_create_surface(compositor)); | 	_surface.reset(wl_compositor_create_surface(compositor)); | ||||||
|     _layerSurface.reset(zwlr_layer_shell_v1_get_layer_surface(wlrLayerShell, | 	_layerSurface.reset(zwlr_layer_shell_v1_get_layer_surface(wlrLayerShell, | ||||||
|         _surface.get(), nullptr, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "net.tapesoftware.Somebar")); | 	_surface.get(), nullptr, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "net.tapesoftware.Somebar")); | ||||||
|     zwlr_layer_surface_v1_add_listener(_layerSurface.get(), &_layerSurfaceListener, this); | 	zwlr_layer_surface_v1_add_listener(_layerSurface.get(), &_layerSurfaceListener, this); | ||||||
|     auto anchor = topbar ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | 	auto anchor = topbar ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | ||||||
|     zwlr_layer_surface_v1_set_anchor(_layerSurface.get(), | 	zwlr_layer_surface_v1_set_anchor(_layerSurface.get(), | ||||||
|         anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); | 	anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); | ||||||
| 
 | 
 | ||||||
|     auto barSize = barfont.height + paddingY * 2; | 	auto barSize = barfont.height + paddingY * 2; | ||||||
|     zwlr_layer_surface_v1_set_size(_layerSurface.get(), 0, barSize); | 	zwlr_layer_surface_v1_set_size(_layerSurface.get(), 0, barSize); | ||||||
|     zwlr_layer_surface_v1_set_exclusive_zone(_layerSurface.get(), barSize); | 	zwlr_layer_surface_v1_set_exclusive_zone(_layerSurface.get(), barSize); | ||||||
|     wl_surface_commit(_surface.get()); | 	wl_surface_commit(_surface.get()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::hide() | void Bar::hide() | ||||||
| { | { | ||||||
|     if (!visible()) return; | 	if (!visible()) return; | ||||||
|     _layerSurface.reset(); | 	_layerSurface.reset(); | ||||||
|     _surface.reset(); | 	_surface.reset(); | ||||||
|     _bufs.reset(); | 	_bufs.reset(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::setTag(int tag, znet_tapesoftware_dwl_wm_monitor_v1_tag_state state, int numClients, int focusedClient) | void Bar::setTag(int tag, znet_tapesoftware_dwl_wm_monitor_v1_tag_state state, int numClients, int focusedClient) | ||||||
| { | { | ||||||
|     auto& t = _tags[tag]; | 	auto& t = _tags[tag]; | ||||||
|     t.state = state; | 	t.state = state; | ||||||
|     t.numClients = numClients; | 	t.numClients = numClients; | ||||||
|     t.focusedClient = focusedClient; | 	t.focusedClient = focusedClient; | ||||||
| } | } | ||||||
| void Bar::setSelected(bool selected) { _selected = selected; } | void Bar::setSelected(bool selected) { _selected = selected; } | ||||||
| void Bar::setLayout(int layout) { _layoutCmp.setText(layoutNames[layout]); } | void Bar::setLayout(int layout) { _layoutCmp.setText(layoutNames[layout]); } | ||||||
| @ -121,142 +121,142 @@ void Bar::setStatus(const std::string& status) { _statusCmp.setText(status); } | |||||||
| 
 | 
 | ||||||
| void Bar::invalidate() | void Bar::invalidate() | ||||||
| { | { | ||||||
|     if (_invalid || !visible()) return; | 	if (_invalid || !visible()) return; | ||||||
|     _invalid = true; | 	_invalid = true; | ||||||
|     auto frame = wl_surface_frame(_surface.get()); | 	auto frame = wl_surface_frame(_surface.get()); | ||||||
|     wl_callback_add_listener(frame, &_frameListener, this); | 	wl_callback_add_listener(frame, &_frameListener, this); | ||||||
|     wl_surface_commit(_surface.get()); | 	wl_surface_commit(_surface.get()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::click(int x, int, int btn) | void Bar::click(int x, int, int btn) | ||||||
| { | { | ||||||
|     Arg arg = {0}; | 	Arg arg = {0}; | ||||||
|     Arg* argp = nullptr; | 	Arg* argp = nullptr; | ||||||
|     int control = ClkNone; | 	int control = ClkNone; | ||||||
|     if (x > _statusCmp.x) { | 	if (x > _statusCmp.x) { | ||||||
|         control = ClkStatusText; | 		control = ClkStatusText; | ||||||
|     } else if (x > _titleCmp.x) { | 	} else if (x > _titleCmp.x) { | ||||||
|         control = ClkWinTitle; | 		control = ClkWinTitle; | ||||||
|     } else if (x > _layoutCmp.x) { | 	} else if (x > _layoutCmp.x) { | ||||||
|         control = ClkLayoutSymbol; | 		control = ClkLayoutSymbol; | ||||||
|     } else for (auto tag = _tags.size()-1; tag >= 0; tag--) { | 	} else for (auto tag = _tags.size()-1; tag >= 0; tag--) { | ||||||
|         if (x > _tags[tag].component.x) { | 		if (x > _tags[tag].component.x) { | ||||||
|             control = ClkTagBar; | 			control = ClkTagBar; | ||||||
|             arg.ui = 1<<tag; | 			arg.ui = 1<<tag; | ||||||
|             argp = &arg; | 			argp = &arg; | ||||||
|             break; | 			break; | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
|     for (auto i = 0u; i < sizeof(buttons)/sizeof(buttons[0]); i++) { | 	for (auto i = 0u; i < sizeof(buttons)/sizeof(buttons[0]); i++) { | ||||||
|         const auto& button = buttons[i]; | 		const auto& button = buttons[i]; | ||||||
|         if (button.control == control && button.btn == btn) { | 		if (button.control == control && button.btn == btn) { | ||||||
|             button.func(*_mon, *(argp ? argp : &button.arg)); | 			button.func(*_mon, *(argp ? argp : &button.arg)); | ||||||
|             return; | 			return; | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height) | void Bar::layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height) | ||||||
| { | { | ||||||
|     zwlr_layer_surface_v1_ack_configure(_layerSurface.get(), serial); | 	zwlr_layer_surface_v1_ack_configure(_layerSurface.get(), serial); | ||||||
|     _bufs.emplace(width, height, WL_SHM_FORMAT_XRGB8888); | 	_bufs.emplace(width, height, WL_SHM_FORMAT_XRGB8888); | ||||||
|     render(); | 	render(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::render() | void Bar::render() | ||||||
| { | { | ||||||
|     if (!visible()) return; | 	if (!visible()) return; | ||||||
|     auto img = wl_unique_ptr<cairo_surface_t> {cairo_image_surface_create_for_data( | 	auto img = wl_unique_ptr<cairo_surface_t> {cairo_image_surface_create_for_data( | ||||||
|         _bufs->data(), | 		_bufs->data(), | ||||||
|         CAIRO_FORMAT_ARGB32, | 		CAIRO_FORMAT_ARGB32, | ||||||
|         _bufs->width, | 		_bufs->width, | ||||||
|         _bufs->height, | 		_bufs->height, | ||||||
|         _bufs->stride | 		_bufs->stride | ||||||
|     )}; | 		)}; | ||||||
|     auto painter = wl_unique_ptr<cairo_t> {cairo_create(img.get())}; | 	auto painter = wl_unique_ptr<cairo_t> {cairo_create(img.get())}; | ||||||
|     _painter = painter.get(); | 	_painter = painter.get(); | ||||||
|     pango_cairo_update_context(_painter, _pangoContext.get()); | 	pango_cairo_update_context(_painter, _pangoContext.get()); | ||||||
|     _x = 0; | 	_x = 0; | ||||||
| 
 | 
 | ||||||
|     renderTags(); | 	renderTags(); | ||||||
|     setColorScheme(_selected ? colorActive : colorInactive); | 	setColorScheme(_selected ? colorActive : colorInactive); | ||||||
|     renderComponent(_layoutCmp); | 	renderComponent(_layoutCmp); | ||||||
|     renderComponent(_titleCmp); | 	renderComponent(_titleCmp); | ||||||
|     renderStatus(); | 	renderStatus(); | ||||||
| 
 | 
 | ||||||
|     _painter = nullptr; | 	_painter = nullptr; | ||||||
|     wl_surface_attach(_surface.get(), _bufs->buffer(), 0, 0); | 	wl_surface_attach(_surface.get(), _bufs->buffer(), 0, 0); | ||||||
|     wl_surface_damage(_surface.get(), 0, 0, INT_MAX, INT_MAX); | 	wl_surface_damage(_surface.get(), 0, 0, INT_MAX, INT_MAX); | ||||||
|     wl_surface_commit(_surface.get()); | 	wl_surface_commit(_surface.get()); | ||||||
|     _bufs->flip(); | 	_bufs->flip(); | ||||||
|     _invalid = false; | 	_invalid = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::renderTags() | void Bar::renderTags() | ||||||
| { | { | ||||||
|     for (auto &tag : _tags) { | 	for (auto &tag : _tags) { | ||||||
|         setColorScheme( | 		setColorScheme( | ||||||
|             tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE ? colorActive : colorInactive, | 		tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE ? colorActive : colorInactive, | ||||||
|             tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_URGENT); | 		tag.state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_URGENT); | ||||||
|         renderComponent(tag.component); | 		renderComponent(tag.component); | ||||||
|         auto indicators = std::min(tag.numClients, _bufs->height/2); | 		auto indicators = std::min(tag.numClients, _bufs->height/2); | ||||||
|         for (auto ind = 0; ind < indicators; ind++) { | 		for (auto ind = 0; ind < indicators; ind++) { | ||||||
|             auto w = ind == tag.focusedClient ? 7 : 1; | 			auto w = ind == tag.focusedClient ? 7 : 1; | ||||||
|             cairo_move_to(_painter, tag.component.x, ind*2+0.5); | 			cairo_move_to(_painter, tag.component.x, ind*2+0.5); | ||||||
|             cairo_rel_line_to(_painter, w, 0); | 			cairo_rel_line_to(_painter, w, 0); | ||||||
|             cairo_close_path(_painter); | 			cairo_close_path(_painter); | ||||||
|             cairo_set_line_width(_painter, 1); | 			cairo_set_line_width(_painter, 1); | ||||||
|             cairo_stroke(_painter); | 			cairo_stroke(_painter); | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::renderStatus() | void Bar::renderStatus() | ||||||
| { | { | ||||||
|     pango_cairo_update_layout(_painter, _statusCmp.pangoLayout.get()); | 	pango_cairo_update_layout(_painter, _statusCmp.pangoLayout.get()); | ||||||
|     beginBg(); | 	beginBg(); | ||||||
|     auto start = _bufs->width - _statusCmp.width() - paddingX*2; | 	auto start = _bufs->width - _statusCmp.width() - paddingX*2; | ||||||
|     cairo_rectangle(_painter, _x, 0, _bufs->width-_x+start, _bufs->height); | 	cairo_rectangle(_painter, _x, 0, _bufs->width-_x+start, _bufs->height); | ||||||
|     cairo_fill(_painter); | 	cairo_fill(_painter); | ||||||
| 
 | 
 | ||||||
|     _x = start; | 	_x = start; | ||||||
|     renderComponent(_statusCmp); | 	renderComponent(_statusCmp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Bar::setColorScheme(const ColorScheme& scheme, bool invert) | void Bar::setColorScheme(const ColorScheme& scheme, bool invert) | ||||||
| { | { | ||||||
|     _colorScheme = invert | 	_colorScheme = invert | ||||||
|         ? ColorScheme {scheme.bg, scheme.fg} | 		? ColorScheme {scheme.bg, scheme.fg} | ||||||
|         : ColorScheme {scheme.fg, scheme.bg}; | 		: ColorScheme {scheme.fg, scheme.bg}; | ||||||
| } | } | ||||||
| static void setColor(cairo_t* painter, const Color& color) | static void setColor(cairo_t* painter, const Color& color) | ||||||
| { | { | ||||||
|     cairo_set_source_rgba(painter, color.r/255.0, color.g/255.0, color.b/255.0, color.a/255.0); | 	cairo_set_source_rgba(painter, color.r/255.0, color.g/255.0, color.b/255.0, color.a/255.0); | ||||||
| } | } | ||||||
| void Bar::beginFg() { setColor(_painter, _colorScheme.fg); } | void Bar::beginFg() { setColor(_painter, _colorScheme.fg); } | ||||||
| void Bar::beginBg() { setColor(_painter, _colorScheme.bg); } | void Bar::beginBg() { setColor(_painter, _colorScheme.bg); } | ||||||
| 
 | 
 | ||||||
| void Bar::renderComponent(BarComponent& component) | void Bar::renderComponent(BarComponent& component) | ||||||
| { | { | ||||||
|     pango_cairo_update_layout(_painter, component.pangoLayout.get()); | 	pango_cairo_update_layout(_painter, component.pangoLayout.get()); | ||||||
|     auto size = component.width() + paddingX*2; | 	auto size = component.width() + paddingX*2; | ||||||
|     component.x = _x; | 	component.x = _x; | ||||||
| 
 | 
 | ||||||
|     beginBg(); | 	beginBg(); | ||||||
|     cairo_rectangle(_painter, _x, 0, size, _bufs->height); | 	cairo_rectangle(_painter, _x, 0, size, _bufs->height); | ||||||
|     cairo_fill(_painter); | 	cairo_fill(_painter); | ||||||
|     cairo_move_to(_painter, _x+paddingX, paddingY); | 	cairo_move_to(_painter, _x+paddingX, paddingY); | ||||||
| 
 | 
 | ||||||
|     beginFg(); | 	beginFg(); | ||||||
|     pango_cairo_show_layout(_painter, component.pangoLayout.get()); | 	pango_cairo_show_layout(_painter, component.pangoLayout.get()); | ||||||
|     _x += size; | 	_x += size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BarComponent Bar::createComponent(const std::string &initial) | BarComponent Bar::createComponent(const std::string &initial) | ||||||
| { | { | ||||||
|     auto layout = pango_layout_new(_pangoContext.get()); | 	auto layout = pango_layout_new(_pangoContext.get()); | ||||||
|     pango_layout_set_font_description(layout, barfont.description); | 	pango_layout_set_font_description(layout, barfont.description); | ||||||
|     auto res = BarComponent {wl_unique_ptr<PangoLayout> {layout}}; | 	auto res = BarComponent {wl_unique_ptr<PangoLayout> {layout}}; | ||||||
|     res.setText(initial); | 	res.setText(initial); | ||||||
|     return res; | 	return res; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										96
									
								
								src/bar.hpp
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/bar.hpp
									
									
									
									
									
								
							| @ -11,65 +11,65 @@ | |||||||
| #include "shm_buffer.hpp" | #include "shm_buffer.hpp" | ||||||
| 
 | 
 | ||||||
| class BarComponent { | class BarComponent { | ||||||
|     std::unique_ptr<std::string> _text; | 	std::unique_ptr<std::string> _text; | ||||||
| public: | public: | ||||||
|     BarComponent(); | 	BarComponent(); | ||||||
|     explicit BarComponent(wl_unique_ptr<PangoLayout> layout); | 	explicit BarComponent(wl_unique_ptr<PangoLayout> layout); | ||||||
|     int width() const; | 	int width() const; | ||||||
|     void setText(const std::string& text); | 	void setText(const std::string& text); | ||||||
|     wl_unique_ptr<PangoLayout> pangoLayout; | 	wl_unique_ptr<PangoLayout> pangoLayout; | ||||||
|     int x {0}; | 	int x {0}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct Tag { | struct Tag { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_tag_state state; | 	znet_tapesoftware_dwl_wm_monitor_v1_tag_state state; | ||||||
|     int numClients; | 	int numClients; | ||||||
|     int focusedClient; | 	int focusedClient; | ||||||
|     BarComponent component; | 	BarComponent component; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct Monitor; | struct Monitor; | ||||||
| class Bar { | class Bar { | ||||||
|     static const zwlr_layer_surface_v1_listener _layerSurfaceListener; | 	static const zwlr_layer_surface_v1_listener _layerSurfaceListener; | ||||||
|     static const wl_callback_listener _frameListener; | 	static const wl_callback_listener _frameListener; | ||||||
| 
 | 
 | ||||||
|     wl_unique_ptr<wl_surface> _surface; | 	wl_unique_ptr<wl_surface> _surface; | ||||||
|     wl_unique_ptr<zwlr_layer_surface_v1> _layerSurface; | 	wl_unique_ptr<zwlr_layer_surface_v1> _layerSurface; | ||||||
|     wl_unique_ptr<PangoContext> _pangoContext; | 	wl_unique_ptr<PangoContext> _pangoContext; | ||||||
|     Monitor* _mon; | 	Monitor* _mon; | ||||||
|     std::optional<ShmBuffer> _bufs; | 	std::optional<ShmBuffer> _bufs; | ||||||
|     std::vector<Tag> _tags; | 	std::vector<Tag> _tags; | ||||||
|     BarComponent _layoutCmp, _titleCmp, _statusCmp; | 	BarComponent _layoutCmp, _titleCmp, _statusCmp; | ||||||
|     bool _selected; | 	bool _selected; | ||||||
|     bool _invalid {false}; | 	bool _invalid {false}; | ||||||
| 
 | 
 | ||||||
|     // only vaild during render()
 | 	// only vaild during render()
 | ||||||
|     cairo_t* _painter {nullptr}; | 	cairo_t* _painter {nullptr}; | ||||||
|     int _x; | 	int _x; | ||||||
|     ColorScheme _colorScheme; | 	ColorScheme _colorScheme; | ||||||
| 
 | 
 | ||||||
|     void layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height); | 	void layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height); | ||||||
|     void render(); | 	void render(); | ||||||
|     void renderTags(); | 	void renderTags(); | ||||||
|     void renderStatus(); | 	void renderStatus(); | ||||||
| 
 | 
 | ||||||
|     // low-level rendering
 | 	// low-level rendering
 | ||||||
|     void setColorScheme(const ColorScheme& scheme, bool invert = false); | 	void setColorScheme(const ColorScheme& scheme, bool invert = false); | ||||||
|     void beginFg(); | 	void beginFg(); | ||||||
|     void beginBg(); | 	void beginBg(); | ||||||
|     void renderComponent(BarComponent& component); | 	void renderComponent(BarComponent& component); | ||||||
|     BarComponent createComponent(const std::string& initial = {}); | 	BarComponent createComponent(const std::string& initial = {}); | ||||||
| public: | public: | ||||||
|     Bar(Monitor *mon); | 	Bar(Monitor *mon); | ||||||
|     const wl_surface* surface() const; | 	const wl_surface* surface() const; | ||||||
|     bool visible() const; | 	bool visible() const; | ||||||
|     void show(wl_output* output); | 	void show(wl_output* output); | ||||||
|     void hide(); | 	void hide(); | ||||||
|     void setTag(int tag, znet_tapesoftware_dwl_wm_monitor_v1_tag_state state, int numClients, int focusedClient); | 	void setTag(int tag, znet_tapesoftware_dwl_wm_monitor_v1_tag_state state, int numClients, int focusedClient); | ||||||
|     void setSelected(bool selected); | 	void setSelected(bool selected); | ||||||
|     void setLayout(int layout); | 	void setLayout(int layout); | ||||||
|     void setTitle(const std::string& title); | 	void setTitle(const std::string& title); | ||||||
|     void setStatus(const std::string& status); | 	void setStatus(const std::string& status); | ||||||
|     void invalidate(); | 	void invalidate(); | ||||||
|     void click(int x, int y, int btn); | 	void click(int x, int y, int btn); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -13,12 +13,12 @@ | |||||||
| #include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" | #include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" | ||||||
| 
 | 
 | ||||||
| struct Color { | struct Color { | ||||||
|     Color() {} | 	Color() {} | ||||||
|     constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255) : r(r), g(g), b(b), a(a) { } | 	constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255) : r(r), g(g), b(b), a(a) { } | ||||||
|     uint8_t r, g, b, a {255}; | 	uint8_t r, g, b, a {255}; | ||||||
| }; | }; | ||||||
| struct ColorScheme { | struct ColorScheme { | ||||||
|     Color fg, bg; | 	Color fg, bg; | ||||||
| }; | }; | ||||||
| union Arg { | union Arg { | ||||||
| 	unsigned int ui; | 	unsigned int ui; | ||||||
| @ -53,8 +53,8 @@ void spawn(Monitor&, const Arg& arg); | |||||||
| template<typename T> | template<typename T> | ||||||
| struct wl_deleter; | struct wl_deleter; | ||||||
| #define WL_DELETER(type, fn) template<> struct wl_deleter<type> { \ | #define WL_DELETER(type, fn) template<> struct wl_deleter<type> { \ | ||||||
|     void operator()(type* v) { if(v) fn(v); } \ | 	void operator()(type* v) { if(v) fn(v); } \ | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
| template<typename T> | template<typename T> | ||||||
| using wl_unique_ptr = std::unique_ptr<T, wl_deleter<T>>; | using wl_unique_ptr = std::unique_ptr<T, wl_deleter<T>>; | ||||||
|  | |||||||
| @ -17,10 +17,10 @@ constexpr ColorScheme colorActive = {Color(0xee, 0xee, 0xee), Color(0x00, 0x55, | |||||||
| constexpr const char* termcmd[] = {"foot", nullptr}; | constexpr const char* termcmd[] = {"foot", nullptr}; | ||||||
| 
 | 
 | ||||||
| constexpr Button buttons[] = { | constexpr Button buttons[] = { | ||||||
|     { ClkTagBar,       BTN_LEFT,   view,       {0} }, | 	{ ClkTagBar,       BTN_LEFT,   view,       {0} }, | ||||||
|     { ClkTagBar,       BTN_RIGHT,  tag,        {0} }, | 	{ ClkTagBar,       BTN_RIGHT,  tag,        {0} }, | ||||||
|     { ClkTagBar,       BTN_MIDDLE, toggletag,  {0} }, | 	{ ClkTagBar,       BTN_MIDDLE, toggletag,  {0} }, | ||||||
|     { ClkLayoutSymbol, BTN_LEFT,   setlayout,  {.ui = 0} }, | 	{ ClkLayoutSymbol, BTN_LEFT,   setlayout,  {.ui = 0} }, | ||||||
|     { ClkLayoutSymbol, BTN_RIGHT,  setlayout,  {.ui = 2} }, | 	{ ClkLayoutSymbol, BTN_RIGHT,  setlayout,  {.ui = 2} }, | ||||||
|     { ClkStatusText,   BTN_RIGHT,  spawn,      {.v = termcmd} }, | 	{ ClkStatusText,   BTN_RIGHT,  spawn,      {.v = termcmd} }, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -9,63 +9,63 @@ | |||||||
| // reads data from Reader, and passes complete lines to Consumer.
 | // reads data from Reader, and passes complete lines to Consumer.
 | ||||||
| template<size_t BufSize> | template<size_t BufSize> | ||||||
| class LineBuffer { | class LineBuffer { | ||||||
|     using Iterator = typename std::array<char, BufSize>::iterator; | 	using Iterator = typename std::array<char, BufSize>::iterator; | ||||||
|     std::array<char, BufSize> _buffer; | 	std::array<char, BufSize> _buffer; | ||||||
|     Iterator _bufferedTo; | 	Iterator _bufferedTo; | ||||||
|     Iterator _consumedTo; | 	Iterator _consumedTo; | ||||||
|     bool _discardLine {false}; | 	bool _discardLine {false}; | ||||||
| public: | public: | ||||||
|     LineBuffer() | 	LineBuffer() | ||||||
|         : _bufferedTo {_buffer.begin()} | 		: _bufferedTo {_buffer.begin()} | ||||||
|         , _consumedTo {_buffer.begin()} | 		, _consumedTo {_buffer.begin()} | ||||||
|     { | 	{ | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
|     template<typename Reader, typename Consumer> | 	template<typename Reader, typename Consumer> | ||||||
|     ssize_t readLines(const Reader& reader, const Consumer& consumer) | 	ssize_t readLines(const Reader& reader, const Consumer& consumer) | ||||||
|     { | 	{ | ||||||
|         while (true) { | 		while (true) { | ||||||
|             auto bytesRead = reader(_bufferedTo, _buffer.end() - _bufferedTo); | 			auto bytesRead = reader(_bufferedTo, _buffer.end() - _bufferedTo); | ||||||
|             if (bytesRead <= 0) { | 			if (bytesRead <= 0) { | ||||||
|                 return bytesRead; | 				return bytesRead; | ||||||
|             } | 			} | ||||||
|             _bufferedTo += bytesRead; | 			_bufferedTo += bytesRead; | ||||||
|             dispatchLines(consumer); | 			dispatchLines(consumer); | ||||||
|             resetBuffer(); | 			resetBuffer(); | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| private: | 	private: | ||||||
|     template<typename Consumer> | 	template<typename Consumer> | ||||||
|     void dispatchLines(const Consumer& consumer) | 	void dispatchLines(const Consumer& consumer) | ||||||
|     { | 	{ | ||||||
|         while (true) { | 		while (true) { | ||||||
|             auto separator = std::find(_consumedTo, _bufferedTo, '\n'); | 			auto separator = std::find(_consumedTo, _bufferedTo, '\n'); | ||||||
|             if (separator == _bufferedTo) { | 			if (separator == _bufferedTo) { | ||||||
|                 break; | 				break; | ||||||
|             } | 			} | ||||||
|             size_t lineLength = separator - _consumedTo; | 			size_t lineLength = separator - _consumedTo; | ||||||
|             if (!_discardLine) { | 			if (!_discardLine) { | ||||||
|                 consumer(_consumedTo, lineLength); | 				consumer(_consumedTo, lineLength); | ||||||
|             } | 			} | ||||||
|             _consumedTo = separator + 1; | 			_consumedTo = separator + 1; | ||||||
|             _discardLine = false; | 			_discardLine = false; | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
|     void resetBuffer() | 	void resetBuffer() | ||||||
|     { | 	{ | ||||||
|         size_t bytesRemaining = _bufferedTo - _consumedTo; | 		size_t bytesRemaining = _bufferedTo - _consumedTo; | ||||||
|         if (bytesRemaining == _buffer.size()) { | 		if (bytesRemaining == _buffer.size()) { | ||||||
|             // line too long
 | 			// line too long
 | ||||||
|             _discardLine = true; | 			_discardLine = true; | ||||||
|             _consumedTo = _buffer.begin(); | 			_consumedTo = _buffer.begin(); | ||||||
|             _bufferedTo = _buffer.begin(); | 			_bufferedTo = _buffer.begin(); | ||||||
|         } else if (bytesRemaining > 0 && _consumedTo > _buffer.begin()) { | 		} else if (bytesRemaining > 0 && _consumedTo > _buffer.begin()) { | ||||||
|             // move the last partial message to the front of the buffer, so a full-sized
 | 			// move the last partial message to the front of the buffer, so a full-sized
 | ||||||
|             // message will fit
 | 			// message will fit
 | ||||||
|             std::copy(_consumedTo, _bufferedTo, _buffer.begin()); | 			std::copy(_consumedTo, _bufferedTo, _buffer.begin()); | ||||||
|             _consumedTo = _buffer.begin(); | 			_consumedTo = _buffer.begin(); | ||||||
|             _bufferedTo = _consumedTo + bytesRemaining; | 			_bufferedTo = _consumedTo + bytesRemaining; | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										778
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										778
									
								
								src/main.cpp
									
									
									
									
									
								
							| @ -26,26 +26,26 @@ | |||||||
| #include "line_buffer.hpp" | #include "line_buffer.hpp" | ||||||
| 
 | 
 | ||||||
| struct Monitor { | struct Monitor { | ||||||
|     uint32_t registryName; | 	uint32_t registryName; | ||||||
|     std::string xdgName; | 	std::string xdgName; | ||||||
|     wl_unique_ptr<wl_output> wlOutput; | 	wl_unique_ptr<wl_output> wlOutput; | ||||||
|     wl_unique_ptr<znet_tapesoftware_dwl_wm_monitor_v1> dwlMonitor; | 	wl_unique_ptr<znet_tapesoftware_dwl_wm_monitor_v1> dwlMonitor; | ||||||
|     std::optional<Bar> bar; | 	std::optional<Bar> bar; | ||||||
|     bool desiredVisibility {true}; | 	bool desiredVisibility {true}; | ||||||
|     bool hasData; | 	bool hasData; | ||||||
|     uint32_t tags; | 	uint32_t tags; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct SeatPointer { | struct SeatPointer { | ||||||
|     wl_unique_ptr<wl_pointer> wlPointer; | 	wl_unique_ptr<wl_pointer> wlPointer; | ||||||
|     Bar* focusedBar; | 	Bar* focusedBar; | ||||||
|     int x, y; | 	int x, y; | ||||||
|     std::vector<int> btns; | 	std::vector<int> btns; | ||||||
| }; | }; | ||||||
| struct Seat { | struct Seat { | ||||||
|     uint32_t name; | 	uint32_t name; | ||||||
|     wl_unique_ptr<wl_seat> wlSeat; | 	wl_unique_ptr<wl_seat> wlSeat; | ||||||
|     std::optional<SeatPointer> pointer; | 	std::optional<SeatPointer> pointer; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void updatemon(Monitor &mon); | static void updatemon(Monitor &mon); | ||||||
| @ -81,238 +81,238 @@ static bool quitting {false}; | |||||||
| 
 | 
 | ||||||
| void view(Monitor& m, const Arg& arg) | void view(Monitor& m, const Arg& arg) | ||||||
| { | { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), arg.ui, 1); | 	znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), arg.ui, 1); | ||||||
| } | } | ||||||
| void toggleview(Monitor& m, const Arg& arg) | void toggleview(Monitor& m, const Arg& arg) | ||||||
| { | { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), m.tags ^ arg.ui, 0); | 	znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), m.tags ^ arg.ui, 0); | ||||||
| } | } | ||||||
| void setlayout(Monitor& m, const Arg& arg) | void setlayout(Monitor& m, const Arg& arg) | ||||||
| { | { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_set_layout(m.dwlMonitor.get(), arg.ui); | 	znet_tapesoftware_dwl_wm_monitor_v1_set_layout(m.dwlMonitor.get(), arg.ui); | ||||||
| } | } | ||||||
| void tag(Monitor& m, const Arg& arg) | void tag(Monitor& m, const Arg& arg) | ||||||
| { | { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), 0, arg.ui); | 	znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), 0, arg.ui); | ||||||
| } | } | ||||||
| void toggletag(Monitor& m, const Arg& arg) | void toggletag(Monitor& m, const Arg& arg) | ||||||
| { | { | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), 0xffffff, arg.ui); | 	znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), 0xffffff, arg.ui); | ||||||
| } | } | ||||||
| void spawn(Monitor&, const Arg& arg) | void spawn(Monitor&, const Arg& arg) | ||||||
| { | { | ||||||
|     if (fork() == 0) { | 	if (fork() == 0) { | ||||||
|         auto argv = static_cast<char* const*>(arg.v); | 		auto argv = static_cast<char* const*>(arg.v); | ||||||
|         setsid(); | 		setsid(); | ||||||
|         execvp(argv[0], argv); | 		execvp(argv[0], argv); | ||||||
|         fprintf(stderr, "somebar: execvp %s ", argv[0]); | 		fprintf(stderr, "somebar: execvp %s ", argv[0]); | ||||||
|         perror(" failed"); | 		perror(" failed"); | ||||||
|         exit(1); | 		exit(1); | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct xdg_wm_base_listener xdgWmBaseListener = { | static const struct xdg_wm_base_listener xdgWmBaseListener = { | ||||||
|     [](void*, xdg_wm_base* sender, uint32_t serial) { | 	[](void*, xdg_wm_base* sender, uint32_t serial) { | ||||||
|         xdg_wm_base_pong(sender, serial); | 		xdg_wm_base_pong(sender, serial); | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct zxdg_output_v1_listener xdgOutputListener = { | static const struct zxdg_output_v1_listener xdgOutputListener = { | ||||||
|     .logical_position = [](void*, zxdg_output_v1*, int, int) { }, | 	.logical_position = [](void*, zxdg_output_v1*, int, int) { }, | ||||||
|     .logical_size = [](void*, zxdg_output_v1*, int, int) { }, | 	.logical_size = [](void*, zxdg_output_v1*, int, int) { }, | ||||||
|     .done = [](void*, zxdg_output_v1*) { }, | 	.done = [](void*, zxdg_output_v1*) { }, | ||||||
|     .name = [](void* mp, zxdg_output_v1* xdgOutput, const char* name) { | 	.name = [](void* mp, zxdg_output_v1* xdgOutput, const char* name) { | ||||||
|         auto& monitor = *static_cast<Monitor*>(mp); | 		auto& monitor = *static_cast<Monitor*>(mp); | ||||||
|         monitor.xdgName = name; | 		monitor.xdgName = name; | ||||||
|         zxdg_output_v1_destroy(xdgOutput); | 		zxdg_output_v1_destroy(xdgOutput); | ||||||
|     }, | 	}, | ||||||
|     .description = [](void*, zxdg_output_v1*, const char*) { }, | 	.description = [](void*, zxdg_output_v1*, const char*) { }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static Bar* barFromSurface(const wl_surface *surface) | static Bar* barFromSurface(const wl_surface *surface) | ||||||
| { | { | ||||||
|     auto mon = std::find_if(begin(monitors), end(monitors), [surface](const Monitor& mon) { | 	auto mon = std::find_if(begin(monitors), end(monitors), [surface](const Monitor& mon) { | ||||||
|         return mon.bar && mon.bar->surface() == surface; | 		return mon.bar && mon.bar->surface() == surface; | ||||||
|     }); | 	}); | ||||||
|     return mon != end(monitors) && mon->bar ? &*mon->bar : nullptr; | 	return mon != end(monitors) && mon->bar ? &*mon->bar : nullptr; | ||||||
| } | } | ||||||
| static const struct wl_pointer_listener pointerListener = { | static const struct wl_pointer_listener pointerListener = { | ||||||
|     .enter = [](void* sp, wl_pointer* pointer, uint32_t serial, | 	.enter = [](void* sp, wl_pointer* pointer, uint32_t serial, | ||||||
|                 wl_surface* surface, wl_fixed_t x, wl_fixed_t y) | 	wl_surface* surface, wl_fixed_t x, wl_fixed_t y) | ||||||
|     { | 	{ | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         seat.pointer->focusedBar = barFromSurface(surface); | 		seat.pointer->focusedBar = barFromSurface(surface); | ||||||
|         if (!cursorImage) { | 		if (!cursorImage) { | ||||||
|             auto cursorTheme = wl_cursor_theme_load(nullptr, 24, shm); | 			auto cursorTheme = wl_cursor_theme_load(nullptr, 24, shm); | ||||||
|             cursorImage = wl_cursor_theme_get_cursor(cursorTheme, "left_ptr")->images[0]; | 			cursorImage = wl_cursor_theme_get_cursor(cursorTheme, "left_ptr")->images[0]; | ||||||
|             cursorSurface = wl_compositor_create_surface(compositor); | 			cursorSurface = wl_compositor_create_surface(compositor); | ||||||
|             wl_surface_attach(cursorSurface, wl_cursor_image_get_buffer(cursorImage), 0, 0); | 			wl_surface_attach(cursorSurface, wl_cursor_image_get_buffer(cursorImage), 0, 0); | ||||||
|             wl_surface_commit(cursorSurface); | 			wl_surface_commit(cursorSurface); | ||||||
|         } | 		} | ||||||
|         wl_pointer_set_cursor(pointer, serial, cursorSurface, | 		wl_pointer_set_cursor(pointer, serial, cursorSurface, | ||||||
|             cursorImage->hotspot_x, cursorImage->hotspot_y); | 		cursorImage->hotspot_x, cursorImage->hotspot_y); | ||||||
|     }, | 	}, | ||||||
|     .leave = [](void* sp, wl_pointer*, uint32_t serial, wl_surface*) { | 	.leave = [](void* sp, wl_pointer*, uint32_t serial, wl_surface*) { | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         seat.pointer->focusedBar = nullptr; | 		seat.pointer->focusedBar = nullptr; | ||||||
|     }, | 	}, | ||||||
|     .motion = [](void* sp, wl_pointer*, uint32_t, wl_fixed_t x, wl_fixed_t y) { | 	.motion = [](void* sp, wl_pointer*, uint32_t, wl_fixed_t x, wl_fixed_t y) { | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         seat.pointer->x = wl_fixed_to_int(x); | 		seat.pointer->x = wl_fixed_to_int(x); | ||||||
|         seat.pointer->y = wl_fixed_to_int(y); | 		seat.pointer->y = wl_fixed_to_int(y); | ||||||
|     }, | 	}, | ||||||
|     .button = [](void* sp, wl_pointer*, uint32_t, uint32_t, uint32_t button, uint32_t pressed) { | 	.button = [](void* sp, wl_pointer*, uint32_t, uint32_t, uint32_t button, uint32_t pressed) { | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         auto it = std::find(begin(seat.pointer->btns), end(seat.pointer->btns), button); | 		auto it = std::find(begin(seat.pointer->btns), end(seat.pointer->btns), button); | ||||||
|         if (pressed == WL_POINTER_BUTTON_STATE_PRESSED && it == end(seat.pointer->btns)) { | 		if (pressed == WL_POINTER_BUTTON_STATE_PRESSED && it == end(seat.pointer->btns)) { | ||||||
|             seat.pointer->btns.push_back(button); | 			seat.pointer->btns.push_back(button); | ||||||
|         } else if (pressed == WL_POINTER_BUTTON_STATE_RELEASED && it != end(seat.pointer->btns)) { | 		} else if (pressed == WL_POINTER_BUTTON_STATE_RELEASED && it != end(seat.pointer->btns)) { | ||||||
|             seat.pointer->btns.erase(it); | 			seat.pointer->btns.erase(it); | ||||||
|         } | 		} | ||||||
|     }, | 	}, | ||||||
|     .axis = [](void* sp, wl_pointer*, uint32_t, uint32_t, wl_fixed_t) { }, | 	.axis = [](void* sp, wl_pointer*, uint32_t, uint32_t, wl_fixed_t) { }, | ||||||
|     .frame = [](void* sp, wl_pointer*) { | 	.frame = [](void* sp, wl_pointer*) { | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         if (!seat.pointer->focusedBar) return; | 		if (!seat.pointer->focusedBar) return; | ||||||
|         for (auto btn : seat.pointer->btns) { | 		for (auto btn : seat.pointer->btns) { | ||||||
|             seat.pointer->focusedBar->click(seat.pointer->x, seat.pointer->y, btn); | 			seat.pointer->focusedBar->click(seat.pointer->x, seat.pointer->y, btn); | ||||||
|         } | 		} | ||||||
|         seat.pointer->btns.clear(); | 		seat.pointer->btns.clear(); | ||||||
|     }, | 	}, | ||||||
|     .axis_source = [](void*, wl_pointer*, uint32_t) { }, | 	.axis_source = [](void*, wl_pointer*, uint32_t) { }, | ||||||
|     .axis_stop = [](void*, wl_pointer*, uint32_t, uint32_t) { }, | 	.axis_stop = [](void*, wl_pointer*, uint32_t, uint32_t) { }, | ||||||
|     .axis_discrete = [](void*, wl_pointer*, uint32_t, int32_t) { }, | 	.axis_discrete = [](void*, wl_pointer*, uint32_t, int32_t) { }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct wl_seat_listener seatListener = { | static const struct wl_seat_listener seatListener = { | ||||||
|     .capabilities = [](void* sp, wl_seat*, uint32_t cap) | 	.capabilities = [](void* sp, wl_seat*, uint32_t cap) | ||||||
|     { | 	{ | ||||||
|         auto& seat = *static_cast<Seat*>(sp); | 		auto& seat = *static_cast<Seat*>(sp); | ||||||
|         auto hasPointer = cap & WL_SEAT_CAPABILITY_POINTER; | 		auto hasPointer = cap & WL_SEAT_CAPABILITY_POINTER; | ||||||
|         if (!seat.pointer && hasPointer) { | 		if (!seat.pointer && hasPointer) { | ||||||
|             auto &pointer = seat.pointer.emplace(); | 			auto &pointer = seat.pointer.emplace(); | ||||||
|             pointer.wlPointer = wl_unique_ptr<wl_pointer> {wl_seat_get_pointer(seat.wlSeat.get())}; | 			pointer.wlPointer = wl_unique_ptr<wl_pointer> {wl_seat_get_pointer(seat.wlSeat.get())}; | ||||||
|             wl_pointer_add_listener(seat.pointer->wlPointer.get(), &pointerListener, &seat); | 			wl_pointer_add_listener(seat.pointer->wlPointer.get(), &pointerListener, &seat); | ||||||
|         } else if (seat.pointer && !hasPointer) { | 		} else if (seat.pointer && !hasPointer) { | ||||||
|             seat.pointer.reset(); | 			seat.pointer.reset(); | ||||||
|         } | 		} | ||||||
|     }, | 	}, | ||||||
|     .name = [](void*, wl_seat*, const char *name) { } | 	.name = [](void*, wl_seat*, const char *name) { } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct znet_tapesoftware_dwl_wm_v1_listener dwlWmListener = { | static const struct znet_tapesoftware_dwl_wm_v1_listener dwlWmListener = { | ||||||
|     .tag = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { | 	.tag = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { | ||||||
|         tagNames.push_back(name); | 		tagNames.push_back(name); | ||||||
|     }, | 	}, | ||||||
|     .layout = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { | 	.layout = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { | ||||||
|         layoutNames.push_back(name); | 		layoutNames.push_back(name); | ||||||
|     }, | 	}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct znet_tapesoftware_dwl_wm_monitor_v1_listener dwlWmMonitorListener { | static const struct znet_tapesoftware_dwl_wm_monitor_v1_listener dwlWmMonitorListener { | ||||||
|     .selected = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t selected) { | 	.selected = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t selected) { | ||||||
|         auto mon = static_cast<Monitor*>(mv); | 		auto mon = static_cast<Monitor*>(mv); | ||||||
|         if (selected) { | 		if (selected) { | ||||||
|             selmon = mon; | 			selmon = mon; | ||||||
|         } else if (selmon == mon) { | 		} else if (selmon == mon) { | ||||||
|             selmon = nullptr; | 			selmon = nullptr; | ||||||
|         } | 		} | ||||||
|         mon->bar->setSelected(selected); | 		mon->bar->setSelected(selected); | ||||||
|     }, | 	}, | ||||||
|     .tag = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t tag, uint32_t state, uint32_t numClients, int32_t focusedClient) { | 	.tag = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t tag, uint32_t state, uint32_t numClients, int32_t focusedClient) { | ||||||
|         auto mon = static_cast<Monitor*>(mv); | 		auto mon = static_cast<Monitor*>(mv); | ||||||
|         mon->bar->setTag(tag, static_cast<znet_tapesoftware_dwl_wm_monitor_v1_tag_state>(state), numClients, focusedClient); | 		mon->bar->setTag(tag, static_cast<znet_tapesoftware_dwl_wm_monitor_v1_tag_state>(state), numClients, focusedClient); | ||||||
|         uint32_t mask = 1 << tag; | 		uint32_t mask = 1 << tag; | ||||||
|         if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE) { | 		if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE) { | ||||||
|             mon->tags |= mask; | 			mon->tags |= mask; | ||||||
|         } else { | 		} else { | ||||||
|             mon->tags &= ~mask; | 			mon->tags &= ~mask; | ||||||
|         } | 		} | ||||||
|     }, | 	}, | ||||||
|     .layout = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t layout) { | 	.layout = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t layout) { | ||||||
|         auto mon = static_cast<Monitor*>(mv); | 		auto mon = static_cast<Monitor*>(mv); | ||||||
|         mon->bar->setLayout(layout); | 		mon->bar->setLayout(layout); | ||||||
|     }, | 	}, | ||||||
|     .title = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, const char* title) { | 	.title = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, const char* title) { | ||||||
|         auto mon = static_cast<Monitor*>(mv); | 		auto mon = static_cast<Monitor*>(mv); | ||||||
|         mon->bar->setTitle(title); | 		mon->bar->setTitle(title); | ||||||
|     }, | 	}, | ||||||
|     .frame = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*) { | 	.frame = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*) { | ||||||
|         auto mon = static_cast<Monitor*>(mv); | 		auto mon = static_cast<Monitor*>(mv); | ||||||
|         mon->hasData = true; | 		mon->hasData = true; | ||||||
|         updatemon(*mon); | 		updatemon(*mon); | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void setupMonitor(Monitor& monitor) { | static void setupMonitor(Monitor& monitor) { | ||||||
|     monitor.dwlMonitor.reset(znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, monitor.wlOutput.get())); | 	monitor.dwlMonitor.reset(znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, monitor.wlOutput.get())); | ||||||
|     monitor.bar.emplace(&monitor); | 	monitor.bar.emplace(&monitor); | ||||||
|     monitor.bar->setStatus(lastStatus); | 	monitor.bar->setStatus(lastStatus); | ||||||
|     auto xdgOutput = zxdg_output_manager_v1_get_xdg_output(xdgOutputManager, monitor.wlOutput.get()); | 	auto xdgOutput = zxdg_output_manager_v1_get_xdg_output(xdgOutputManager, monitor.wlOutput.get()); | ||||||
|     zxdg_output_v1_add_listener(xdgOutput, &xdgOutputListener, &monitor); | 	zxdg_output_v1_add_listener(xdgOutput, &xdgOutputListener, &monitor); | ||||||
|     znet_tapesoftware_dwl_wm_monitor_v1_add_listener(monitor.dwlMonitor.get(), &dwlWmMonitorListener, &monitor); | 	znet_tapesoftware_dwl_wm_monitor_v1_add_listener(monitor.dwlMonitor.get(), &dwlWmMonitorListener, &monitor); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void updatemon(Monitor& mon) | static void updatemon(Monitor& mon) | ||||||
| { | { | ||||||
|     if (!mon.hasData) return; | 	if (!mon.hasData) return; | ||||||
|     if (mon.desiredVisibility) { | 	if (mon.desiredVisibility) { | ||||||
|         if (mon.bar->visible()) { | 		if (mon.bar->visible()) { | ||||||
|             mon.bar->invalidate(); | 			mon.bar->invalidate(); | ||||||
|         } else { | 		} else { | ||||||
|             mon.bar->show(mon.wlOutput.get()); | 			mon.bar->show(mon.wlOutput.get()); | ||||||
|         } | 		} | ||||||
|     } else if (mon.bar->visible()) { | 	} else if (mon.bar->visible()) { | ||||||
|         mon.bar->hide(); | 		mon.bar->hide(); | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // called after we have received the initial batch of globals
 | // called after we have received the initial batch of globals
 | ||||||
| static void onReady() | static void onReady() | ||||||
| { | { | ||||||
|     requireGlobal(compositor, "wl_compositor"); | 	requireGlobal(compositor, "wl_compositor"); | ||||||
|     requireGlobal(shm, "wl_shm"); | 	requireGlobal(shm, "wl_shm"); | ||||||
|     requireGlobal(wlrLayerShell, "zwlr_layer_shell_v1"); | 	requireGlobal(wlrLayerShell, "zwlr_layer_shell_v1"); | ||||||
|     requireGlobal(xdgOutputManager, "zxdg_output_manager_v1"); | 	requireGlobal(xdgOutputManager, "zxdg_output_manager_v1"); | ||||||
|     requireGlobal(dwlWm, "znet_tapesoftware_dwl_wm_v1"); | 	requireGlobal(dwlWm, "znet_tapesoftware_dwl_wm_v1"); | ||||||
|     setupStatusFifo(); | 	setupStatusFifo(); | ||||||
|     wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc.
 | 	wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc.
 | ||||||
|     ready = true; | 	ready = true; | ||||||
|     for (auto& monitor : monitors) { | 	for (auto& monitor : monitors) { | ||||||
|         setupMonitor(monitor); | 		setupMonitor(monitor); | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void setupStatusFifo() | static void setupStatusFifo() | ||||||
| { | { | ||||||
|     for (auto i=0; i<100; i++) { | 	for (auto i=0; i<100; i++) { | ||||||
|         auto path = std::string{getenv("XDG_RUNTIME_DIR")} + "/somebar-" + std::to_string(i); | 		auto path = std::string{getenv("XDG_RUNTIME_DIR")} + "/somebar-" + std::to_string(i); | ||||||
|         auto result = mkfifo(path.c_str(), 0666); | 		auto result = mkfifo(path.c_str(), 0666); | ||||||
|         if (result == 0) { | 		if (result == 0) { | ||||||
|             auto fd = open(path.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY); | 			auto fd = open(path.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY); | ||||||
|             if (fd < 0) { | 			if (fd < 0) { | ||||||
|                 diesys("open status fifo reader"); | 				diesys("open status fifo reader"); | ||||||
|             } | 			} | ||||||
|             statusFifoName = path; | 			statusFifoName = path; | ||||||
|             statusFifoFd = fd; | 			statusFifoFd = fd; | ||||||
| 
 | 
 | ||||||
|             fd = open(path.c_str(), O_CLOEXEC | O_WRONLY); | 			fd = open(path.c_str(), O_CLOEXEC | O_WRONLY); | ||||||
|             if (fd < 0) { | 			if (fd < 0) { | ||||||
|                 diesys("open status fifo writer"); | 				diesys("open status fifo writer"); | ||||||
|             } | 			} | ||||||
|             statusFifoWriter = fd; | 			statusFifoWriter = fd; | ||||||
| 
 | 
 | ||||||
|             epoll_event ev = {0}; | 			epoll_event ev = {0}; | ||||||
|             ev.events = EPOLLIN; | 			ev.events = EPOLLIN; | ||||||
|             ev.data.fd = statusFifoFd; | 			ev.data.fd = statusFifoFd; | ||||||
|             if (epoll_ctl(epoll, EPOLL_CTL_ADD, statusFifoFd, &ev) < 0) { | 			if (epoll_ctl(epoll, EPOLL_CTL_ADD, statusFifoFd, &ev) < 0) { | ||||||
|                 diesys("epoll_ctl add status fifo"); | 				diesys("epoll_ctl add status fifo"); | ||||||
|             } | 			} | ||||||
|             return; | 			return; | ||||||
|         } else if (errno != EEXIST) { | 		} else if (errno != EEXIST) { | ||||||
|             diesys("mkfifo"); | 			diesys("mkfifo"); | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const std::string prefixStatus = "status "; | const std::string prefixStatus = "status "; | ||||||
| @ -325,243 +325,243 @@ const std::string argSelected = "selected"; | |||||||
| template<typename T> | template<typename T> | ||||||
| static void updateVisibility(const std::string& name, T updater) | static void updateVisibility(const std::string& name, T updater) | ||||||
| { | { | ||||||
|     auto isCurrent = name == argSelected; | 	auto isCurrent = name == argSelected; | ||||||
|     auto isAll = name == argAll; | 	auto isAll = name == argAll; | ||||||
|     for (auto& mon : monitors) { | 	for (auto& mon : monitors) { | ||||||
|         if (isAll || | 		if (isAll || | ||||||
|             isCurrent && &mon == selmon || | 			isCurrent && &mon == selmon || | ||||||
|             mon.xdgName == name) { | 			mon.xdgName == name) { | ||||||
|             auto newVisibility = updater(mon.desiredVisibility); | 			auto newVisibility = updater(mon.desiredVisibility); | ||||||
|             if (newVisibility != mon.desiredVisibility) { | 			if (newVisibility != mon.desiredVisibility) { | ||||||
|                 mon.desiredVisibility = newVisibility; | 				mon.desiredVisibility = newVisibility; | ||||||
|                 updatemon(mon); | 				updatemon(mon); | ||||||
|             } | 			} | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static LineBuffer<512> _statusBuffer; | static LineBuffer<512> _statusBuffer; | ||||||
| static void onStatus() | static void onStatus() | ||||||
| { | { | ||||||
|     _statusBuffer.readLines( | 	_statusBuffer.readLines( | ||||||
|         [](void* p, size_t size) { | 	[](void* p, size_t size) { | ||||||
|             return read(statusFifoFd, p, size); | 		return read(statusFifoFd, p, size); | ||||||
|         }, | 	}, | ||||||
|         [](const char* buffer, size_t n) { | 	[](const char* buffer, size_t n) { | ||||||
|             auto str = std::string {buffer, n}; | 		auto str = std::string {buffer, n}; | ||||||
|             if (str.rfind(prefixStatus, 0) == 0) { | 		if (str.rfind(prefixStatus, 0) == 0) { | ||||||
|                 lastStatus = str.substr(prefixStatus.size()); | 			lastStatus = str.substr(prefixStatus.size()); | ||||||
|                 for (auto &monitor : monitors) { | 			for (auto &monitor : monitors) { | ||||||
|                     if (monitor.bar) { | 				if (monitor.bar) { | ||||||
|                         monitor.bar->setStatus(lastStatus); | 					monitor.bar->setStatus(lastStatus); | ||||||
|                         monitor.bar->invalidate(); | 					monitor.bar->invalidate(); | ||||||
|                     } | 				} | ||||||
|                 } | 			} | ||||||
|             } else if (str.rfind(prefixShow, 0) == 0) { | 		} else if (str.rfind(prefixShow, 0) == 0) { | ||||||
|                 updateVisibility(str.substr(prefixShow.size()), [](bool) { return true; }); | 			updateVisibility(str.substr(prefixShow.size()), [](bool) { return true; }); | ||||||
|             } else if (str.rfind(prefixHide, 0) == 0) { | 		} else if (str.rfind(prefixHide, 0) == 0) { | ||||||
|                 updateVisibility(str.substr(prefixHide.size()), [](bool) { return false; }); | 			updateVisibility(str.substr(prefixHide.size()), [](bool) { return false; }); | ||||||
|             } else if (str.rfind(prefixToggle, 0) == 0) { | 		} else if (str.rfind(prefixToggle, 0) == 0) { | ||||||
|                 updateVisibility(str.substr(prefixToggle.size()), [](bool vis) { return !vis; }); | 			updateVisibility(str.substr(prefixToggle.size()), [](bool vis) { return !vis; }); | ||||||
|             } | 		} | ||||||
|         }); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct HandleGlobalHelper { | struct HandleGlobalHelper { | ||||||
|     wl_registry* registry; | 	wl_registry* registry; | ||||||
|     uint32_t name; | 	uint32_t name; | ||||||
|     const char* interface; | 	const char* interface; | ||||||
| 
 | 
 | ||||||
|     template<typename T> | 	template<typename T> | ||||||
|     bool handle(T& store, const wl_interface& iface, int version) { | 	bool handle(T& store, const wl_interface& iface, int version) { | ||||||
|         if (strcmp(interface, iface.name)) return false; | 		if (strcmp(interface, iface.name)) return false; | ||||||
|         store = static_cast<T>(wl_registry_bind(registry, name, &iface, version)); | 		store = static_cast<T>(wl_registry_bind(registry, name, &iface, version)); | ||||||
|         return true; | 		return true; | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| static void registryHandleGlobal(void*, wl_registry* registry, uint32_t name, const char* interface, uint32_t version) | static void registryHandleGlobal(void*, wl_registry* registry, uint32_t name, const char* interface, uint32_t version) | ||||||
| { | { | ||||||
|     auto reg = HandleGlobalHelper { registry, name, interface }; | 	auto reg = HandleGlobalHelper { registry, name, interface }; | ||||||
|     if (reg.handle(compositor, wl_compositor_interface, 4)) return; | 	if (reg.handle(compositor, wl_compositor_interface, 4)) return; | ||||||
|     if (reg.handle(shm, wl_shm_interface, 1)) return; | 	if (reg.handle(shm, wl_shm_interface, 1)) return; | ||||||
|     if (reg.handle(wlrLayerShell, zwlr_layer_shell_v1_interface, 4)) return; | 	if (reg.handle(wlrLayerShell, zwlr_layer_shell_v1_interface, 4)) return; | ||||||
|     if (reg.handle(xdgOutputManager, zxdg_output_manager_v1_interface, 3)) return; | 	if (reg.handle(xdgOutputManager, zxdg_output_manager_v1_interface, 3)) return; | ||||||
|     if (reg.handle(xdgWmBase, xdg_wm_base_interface, 2)) { | 	if (reg.handle(xdgWmBase, xdg_wm_base_interface, 2)) { | ||||||
|         xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); | 		xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); | ||||||
|         return; | 		return; | ||||||
|     } | 	} | ||||||
|     if (reg.handle(dwlWm, znet_tapesoftware_dwl_wm_v1_interface, 1)) { | 	if (reg.handle(dwlWm, znet_tapesoftware_dwl_wm_v1_interface, 1)) { | ||||||
|         znet_tapesoftware_dwl_wm_v1_add_listener(dwlWm, &dwlWmListener, nullptr); | 		znet_tapesoftware_dwl_wm_v1_add_listener(dwlWm, &dwlWmListener, nullptr); | ||||||
|         return; | 		return; | ||||||
|     } | 	} | ||||||
|     if (wl_seat *wlSeat; reg.handle(wlSeat, wl_seat_interface, 7)) { | 	if (wl_seat *wlSeat; reg.handle(wlSeat, wl_seat_interface, 7)) { | ||||||
|         auto& seat = seats.emplace_back(Seat {name, wl_unique_ptr<wl_seat> {wlSeat}}); | 		auto& seat = seats.emplace_back(Seat {name, wl_unique_ptr<wl_seat> {wlSeat}}); | ||||||
|         wl_seat_add_listener(wlSeat, &seatListener, &seat); | 		wl_seat_add_listener(wlSeat, &seatListener, &seat); | ||||||
|         return; | 		return; | ||||||
|     } | 	} | ||||||
|     if (wl_output *output; reg.handle(output, wl_output_interface, 1)) { | 	if (wl_output *output; reg.handle(output, wl_output_interface, 1)) { | ||||||
|         auto& m = monitors.emplace_back(Monitor {name, {}, wl_unique_ptr<wl_output> {output}}); | 		auto& m = monitors.emplace_back(Monitor {name, {}, wl_unique_ptr<wl_output> {output}}); | ||||||
|         if (ready) { | 		if (ready) { | ||||||
|             setupMonitor(m); | 			setupMonitor(m); | ||||||
|         } | 		} | ||||||
|         return; | 		return; | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| static void registryHandleRemove(void*, wl_registry* registry, uint32_t name) | static void registryHandleRemove(void*, wl_registry* registry, uint32_t name) | ||||||
| { | { | ||||||
|     monitors.remove_if([name](const Monitor &mon) { return mon.registryName == name; }); | 	monitors.remove_if([name](const Monitor &mon) { return mon.registryName == name; }); | ||||||
|     seats.remove_if([name](const Seat &seat) { return seat.name == name; }); | 	seats.remove_if([name](const Seat &seat) { return seat.name == name; }); | ||||||
| } | } | ||||||
| static const struct wl_registry_listener registry_listener = { | static const struct wl_registry_listener registry_listener = { | ||||||
|     .global = registryHandleGlobal, | 	.global = registryHandleGlobal, | ||||||
|     .global_remove = registryHandleRemove, | 	.global_remove = registryHandleRemove, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int main(int argc, char* argv[]) | int main(int argc, char* argv[]) | ||||||
| { | { | ||||||
|     int opt; | 	int opt; | ||||||
|     while ((opt = getopt(argc, argv, "chv")) != -1) { | 	while ((opt = getopt(argc, argv, "chv")) != -1) { | ||||||
|         switch (opt) { | 		switch (opt) { | ||||||
|             case 'h': | 			case 'h': | ||||||
|                 printf("Usage: %s [-h] [-v] [-c command]\n", argv[0]); | 				printf("Usage: %s [-h] [-v] [-c command]\n", argv[0]); | ||||||
|                 printf("  -h: Show this help\n"); | 				printf("  -h: Show this help\n"); | ||||||
|                 printf("  -v: Show somebar version\n"); | 				printf("  -v: Show somebar version\n"); | ||||||
|                 printf("  -c: Sends a command to sombar. See README for details.\n"); | 				printf("  -c: Sends a command to sombar. See README for details.\n"); | ||||||
|                 printf("If any of these are specified, somebar exits after the action.\n"); | 				printf("If any of these are specified, somebar exits after the action.\n"); | ||||||
|                 printf("Otherwise, somebar will display itself.\n"); | 				printf("Otherwise, somebar will display itself.\n"); | ||||||
|                 exit(0); | 				exit(0); | ||||||
|             case 'v': | 			case 'v': | ||||||
|                 printf("somebar " SOMEBAR_VERSION "\n"); | 				printf("somebar " SOMEBAR_VERSION "\n"); | ||||||
|                 exit(0); | 				exit(0); | ||||||
|             case 'c': | 			case 'c': | ||||||
|                 if (optind >= argc) { | 				if (optind >= argc) { | ||||||
|                     die("Expected command"); | 					die("Expected command"); | ||||||
|                 } | 				} | ||||||
|                 auto path = std::string {getenv("XDG_RUNTIME_DIR")} + "/somebar-0"; | 				auto path = std::string {getenv("XDG_RUNTIME_DIR")} + "/somebar-0"; | ||||||
|                 int fd = open(path.c_str(), O_WRONLY | O_CLOEXEC); | 				int fd = open(path.c_str(), O_WRONLY | O_CLOEXEC); | ||||||
|                 if (fd < 0) { | 				if (fd < 0) { | ||||||
|                     fprintf(stderr, "could not open %s: ", path.c_str()); | 					fprintf(stderr, "could not open %s: ", path.c_str()); | ||||||
|                     perror(""); | 					perror(""); | ||||||
|                     exit(1); | 					exit(1); | ||||||
|                 } | 				} | ||||||
|                 auto str = std::string {}; | 				auto str = std::string {}; | ||||||
|                 for (auto i = optind; i<argc; i++) { | 				for (auto i = optind; i<argc; i++) { | ||||||
|                     if (i > optind) str += " "; | 					if (i > optind) str += " "; | ||||||
|                     str += argv[i]; | 					str += argv[i]; | ||||||
|                 } | 				} | ||||||
|                 str += "\n"; | 				str += "\n"; | ||||||
|                 write(fd, str.c_str(), str.size()); | 				write(fd, str.c_str(), str.size()); | ||||||
|                 exit(0); | 				exit(0); | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
|     static sigset_t blockedsigs; | 	static sigset_t blockedsigs; | ||||||
|     sigemptyset(&blockedsigs); | 	sigemptyset(&blockedsigs); | ||||||
|     sigaddset(&blockedsigs, SIGINT); | 	sigaddset(&blockedsigs, SIGINT); | ||||||
|     sigaddset(&blockedsigs, SIGTERM); | 	sigaddset(&blockedsigs, SIGTERM); | ||||||
|     sigprocmask(SIG_BLOCK, &blockedsigs, nullptr); | 	sigprocmask(SIG_BLOCK, &blockedsigs, nullptr); | ||||||
| 
 | 
 | ||||||
|     epoll_event epollEv = {0}; | 	epoll_event epollEv = {0}; | ||||||
|     std::array<epoll_event, 5> epollEvents; | 	std::array<epoll_event, 5> epollEvents; | ||||||
|     epoll = epoll_create1(EPOLL_CLOEXEC); | 	epoll = epoll_create1(EPOLL_CLOEXEC); | ||||||
|     if (epoll < 0) { | 	if (epoll < 0) { | ||||||
|         diesys("epoll_create1"); | 		diesys("epoll_create1"); | ||||||
|     } | 	} | ||||||
|     int sfd = signalfd(-1, &blockedsigs, SFD_CLOEXEC | SFD_NONBLOCK); | 	int sfd = signalfd(-1, &blockedsigs, SFD_CLOEXEC | SFD_NONBLOCK); | ||||||
|     if (sfd < 0) { | 	if (sfd < 0) { | ||||||
|         diesys("signalfd"); | 		diesys("signalfd"); | ||||||
|     } | 	} | ||||||
|     epollEv.events = EPOLLIN; | 	epollEv.events = EPOLLIN; | ||||||
|     epollEv.data.fd = sfd; | 	epollEv.data.fd = sfd; | ||||||
|     if (epoll_ctl(epoll, EPOLL_CTL_ADD, sfd, &epollEv) < 0) { | 	if (epoll_ctl(epoll, EPOLL_CTL_ADD, sfd, &epollEv) < 0) { | ||||||
|         diesys("epoll_ctl add signalfd"); | 		diesys("epoll_ctl add signalfd"); | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
|     display = wl_display_connect(nullptr); | 	display = wl_display_connect(nullptr); | ||||||
|     if (!display) { | 	if (!display) { | ||||||
|         die("Failed to connect to Wayland display"); | 		die("Failed to connect to Wayland display"); | ||||||
|     } | 	} | ||||||
|     displayFd = wl_display_get_fd(display); | 	displayFd = wl_display_get_fd(display); | ||||||
| 
 | 
 | ||||||
|     auto registry = wl_display_get_registry(display); | 	auto registry = wl_display_get_registry(display); | ||||||
|     wl_registry_add_listener(registry, ®istry_listener, nullptr); | 	wl_registry_add_listener(registry, ®istry_listener, nullptr); | ||||||
|     wl_display_roundtrip(display); | 	wl_display_roundtrip(display); | ||||||
|     onReady(); | 	onReady(); | ||||||
| 
 | 
 | ||||||
|     epollEv.events = EPOLLIN; | 	epollEv.events = EPOLLIN; | ||||||
|     epollEv.data.fd = displayFd; | 	epollEv.data.fd = displayFd; | ||||||
|     if (epoll_ctl(epoll, EPOLL_CTL_ADD, displayFd, &epollEv) < 0) { | 	if (epoll_ctl(epoll, EPOLL_CTL_ADD, displayFd, &epollEv) < 0) { | ||||||
|         diesys("epoll_ctl add wayland_display"); | 		diesys("epoll_ctl add wayland_display"); | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
|     while (!quitting) { | 	while (!quitting) { | ||||||
|         waylandFlush(); | 		waylandFlush(); | ||||||
|         auto res = epoll_wait(epoll, epollEvents.data(), epollEvents.size(), -1); | 		auto res = epoll_wait(epoll, epollEvents.data(), epollEvents.size(), -1); | ||||||
|         if (res < 0) { | 		if (res < 0) { | ||||||
|             if (errno != EINTR) { | 			if (errno != EINTR) { | ||||||
|                 diesys("epoll_wait"); | 				diesys("epoll_wait"); | ||||||
|             } | 			} | ||||||
|         } else { | 		} else { | ||||||
|             for (auto i=0; i<res; i++) { | 			for (auto i=0; i<res; i++) { | ||||||
|                 auto &ev = epollEvents[i]; | 				auto &ev = epollEvents[i]; | ||||||
|                 if (ev.data.fd == displayFd) { | 				if (ev.data.fd == displayFd) { | ||||||
|                     if (ev.events & EPOLLIN) { | 					if (ev.events & EPOLLIN) { | ||||||
|                         if (wl_display_dispatch(display) < 0) { | 						if (wl_display_dispatch(display) < 0) { | ||||||
|                             die("wl_display_dispatch"); | 							die("wl_display_dispatch"); | ||||||
|                         } | 						} | ||||||
|                     } if (ev.events & EPOLLOUT) { | 					} if (ev.events & EPOLLOUT) { | ||||||
|                         epollEv.events = EPOLLIN; | 						epollEv.events = EPOLLIN; | ||||||
|                         epollEv.data.fd = displayFd; | 						epollEv.data.fd = displayFd; | ||||||
|                         if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &epollEv) < 0) { | 						if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &epollEv) < 0) { | ||||||
|                             diesys("epoll_ctl"); | 							diesys("epoll_ctl"); | ||||||
|                         } | 						} | ||||||
|                         waylandFlush(); | 						waylandFlush(); | ||||||
|                     } | 					} | ||||||
|                 } else if (ev.data.fd == statusFifoFd) { | 				} else if (ev.data.fd == statusFifoFd) { | ||||||
|                     onStatus(); | 					onStatus(); | ||||||
|                 } else if (ev.data.fd == sfd) { | 				} else if (ev.data.fd == sfd) { | ||||||
|                     quitting = true; | 					quitting = true; | ||||||
|                 } | 				} | ||||||
|             } | 			} | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
|     cleanup(); | 	cleanup(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void requireGlobal(const void *p, const char *name) | void requireGlobal(const void *p, const char *name) | ||||||
| { | { | ||||||
|     if (p) return; | 	if (p) return; | ||||||
|     fprintf(stderr, "Wayland compositor does not export required global %s, aborting.\n", name); | 	fprintf(stderr, "Wayland compositor does not export required global %s, aborting.\n", name); | ||||||
|     cleanup(); | 	cleanup(); | ||||||
|     exit(1); | 	exit(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void waylandFlush() | void waylandFlush() | ||||||
| { | { | ||||||
|     wl_display_dispatch_pending(display); | 	wl_display_dispatch_pending(display); | ||||||
|     if (wl_display_flush(display) < 0 && errno == EAGAIN) { | 	if (wl_display_flush(display) < 0 && errno == EAGAIN) { | ||||||
|         epoll_event ev = {0}; | 		epoll_event ev = {0}; | ||||||
|         ev.events = EPOLLIN | EPOLLOUT; | 		ev.events = EPOLLIN | EPOLLOUT; | ||||||
|         ev.data.fd = displayFd; | 		ev.data.fd = displayFd; | ||||||
|         if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &ev) < 0) { | 		if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &ev) < 0) { | ||||||
|             diesys("epoll_ctl"); | 			diesys("epoll_ctl"); | ||||||
|         } | 		} | ||||||
|     } | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void die(const char* why) { | void die(const char* why) { | ||||||
|     fprintf(stderr, "%s\n", why); | 	fprintf(stderr, "%s\n", why); | ||||||
|     cleanup(); | 	cleanup(); | ||||||
|     exit(1); | 	exit(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void diesys(const char* why) { | void diesys(const char* why) { | ||||||
|     perror(why); | 	perror(why); | ||||||
|     cleanup(); | 	cleanup(); | ||||||
|     exit(1); | 	exit(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cleanup() { | void cleanup() { | ||||||
|     if (!statusFifoName.empty()) { | 	if (!statusFifoName.empty()) { | ||||||
|         unlink(statusFifoName.c_str()); | 		unlink(statusFifoName.c_str()); | ||||||
|     } | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,26 +9,26 @@ | |||||||
| constexpr int n = 2; | constexpr int n = 2; | ||||||
| 
 | 
 | ||||||
| ShmBuffer::ShmBuffer(int w, int h, wl_shm_format format) | ShmBuffer::ShmBuffer(int w, int h, wl_shm_format format) | ||||||
|     : width(w) | 	: width(w) | ||||||
|     , height(h) | 	, height(h) | ||||||
|     , stride(w*4) | 	, stride(w*4) | ||||||
| { | { | ||||||
|     auto oneSize = stride*size_t(h); | 	auto oneSize = stride*size_t(h); | ||||||
|     auto totalSize = oneSize * n; | 	auto totalSize = oneSize * n; | ||||||
|     auto fd = memfd_create("wl_shm", MFD_CLOEXEC); | 	auto fd = memfd_create("wl_shm", MFD_CLOEXEC); | ||||||
|     ftruncate(fd, totalSize); | 	ftruncate(fd, totalSize); | ||||||
|     auto pool = wl_shm_create_pool(shm, fd, totalSize); | 	auto pool = wl_shm_create_pool(shm, fd, totalSize); | ||||||
|     auto ptr = reinterpret_cast<uint8_t*>(mmap(nullptr, totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); | 	auto ptr = reinterpret_cast<uint8_t*>(mmap(nullptr, totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); | ||||||
|     _mapping = MemoryMapping {ptr, totalSize}; | 	_mapping = MemoryMapping {ptr, totalSize}; | ||||||
|     close(fd); | 	close(fd); | ||||||
|     for (auto i=0; i<n; i++) { | 	for (auto i=0; i<n; i++) { | ||||||
|         auto offset = oneSize*i; | 		auto offset = oneSize*i; | ||||||
|         _buffers[i] = { | 		_buffers[i] = { | ||||||
|             ptr+offset, | 			ptr+offset, | ||||||
|             wl_unique_ptr<wl_buffer> { wl_shm_pool_create_buffer(pool, offset, width, height, stride, format) }, | 			wl_unique_ptr<wl_buffer> { wl_shm_pool_create_buffer(pool, offset, width, height, stride, format) }, | ||||||
|         }; | 		}; | ||||||
|     } | 	} | ||||||
|     wl_shm_pool_destroy(pool); | 	wl_shm_pool_destroy(pool); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t* ShmBuffer::data() { return _buffers[_current].data; } | uint8_t* ShmBuffer::data() { return _buffers[_current].data; } | ||||||
|  | |||||||
| @ -8,38 +8,38 @@ | |||||||
| #include "common.hpp" | #include "common.hpp" | ||||||
| 
 | 
 | ||||||
| class MemoryMapping { | class MemoryMapping { | ||||||
|     void* _ptr {nullptr}; | 	void* _ptr {nullptr}; | ||||||
|     size_t _size {0}; | 	size_t _size {0}; | ||||||
| public: | public: | ||||||
|     MemoryMapping() { } | 	MemoryMapping() { } | ||||||
|     explicit MemoryMapping(void* ptr, size_t size) : _ptr(ptr), _size(size) { } | 	explicit MemoryMapping(void* ptr, size_t size) : _ptr(ptr), _size(size) { } | ||||||
|     MemoryMapping(const MemoryMapping&) = delete; | 	MemoryMapping(const MemoryMapping&) = delete; | ||||||
|     MemoryMapping(MemoryMapping&& other) { swap(other); } | 	MemoryMapping(MemoryMapping&& other) { swap(other); } | ||||||
|     MemoryMapping& operator=(const MemoryMapping& other) = delete; | 	MemoryMapping& operator=(const MemoryMapping& other) = delete; | ||||||
|     MemoryMapping& operator=(MemoryMapping&& other) { swap(other); return *this; } | 	MemoryMapping& operator=(MemoryMapping&& other) { swap(other); return *this; } | ||||||
|     ~MemoryMapping() { if (_ptr) munmap(_ptr, _size); } | 	~MemoryMapping() { if (_ptr) munmap(_ptr, _size); } | ||||||
|     void swap(MemoryMapping &other) { | 	void swap(MemoryMapping &other) { | ||||||
|         using std::swap; | 		using std::swap; | ||||||
|         swap(_ptr, other._ptr); | 		swap(_ptr, other._ptr); | ||||||
|         swap(_size, other._size); | 		swap(_size, other._size); | ||||||
|     } | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // double buffered shm
 | // double buffered shm
 | ||||||
| // format is must be 32-bit
 | // format is must be 32-bit
 | ||||||
| class ShmBuffer { | class ShmBuffer { | ||||||
|     struct Buf { | 	struct Buf { | ||||||
|         uint8_t* data {nullptr}; | 		uint8_t* data {nullptr}; | ||||||
|         wl_unique_ptr<wl_buffer> buffer; | 		wl_unique_ptr<wl_buffer> buffer; | ||||||
|     }; | 	}; | ||||||
|     std::array<Buf, 2> _buffers; | 	std::array<Buf, 2> _buffers; | ||||||
|     int _current {0}; | 	int _current {0}; | ||||||
|     MemoryMapping _mapping; | 	MemoryMapping _mapping; | ||||||
| public: | public: | ||||||
|     int width, height, stride; | 	int width, height, stride; | ||||||
| 
 | 
 | ||||||
|     explicit ShmBuffer(int width, int height, wl_shm_format format); | 	explicit ShmBuffer(int width, int height, wl_shm_format format); | ||||||
|     uint8_t* data(); | 	uint8_t* data(); | ||||||
|     wl_buffer* buffer(); | 	wl_buffer* buffer(); | ||||||
|     void flip(); | 	void flip(); | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user