mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:42:43 +00:00 
			
		
		
		
	 f2609281a3
			
		
	
	
		f2609281a3
		
	
	
	
	
		
			
			Inspector was deleted a long time ago in commit
16c47ccff6, and likely isn't coming back
any time soon.
		
	
			
		
			
				
	
	
		
			184 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Richard Gráčik <r.gracik@gmail.com>
 | |
|  * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include "CatDog.h"
 | |
| #include <LibCore/File.h>
 | |
| #include <LibCore/ProcessStatisticsReader.h>
 | |
| #include <LibGUI/Painter.h>
 | |
| #include <LibGUI/Window.h>
 | |
| 
 | |
| ErrorOr<NonnullRefPtr<CatDog>> CatDog::create()
 | |
| {
 | |
|     struct ImageSource {
 | |
|         State state;
 | |
|         StringView path;
 | |
|     };
 | |
| 
 | |
|     // NOTE: The order of the elements is important. Matching is done in best-match order.
 | |
|     //       So items with the more bits should be placed before items with less bits to
 | |
|     //       ensure correct matching order. This also means that "Frame2" has to be first.
 | |
|     static constexpr Array<ImageSource, 24> const image_sources = {
 | |
|         ImageSource { State::Up | State::Right | State::Frame2, "/res/graphics/catdog/nerun2.png"sv },
 | |
|         { State::Up | State::Right, "/res/graphics/catdog/nerun1.png"sv },
 | |
|         { State::Up | State::Left | State::Frame2, "/res/graphics/catdog/nwrun2.png"sv },
 | |
|         { State::Up | State::Left, "/res/graphics/catdog/nwrun1.png"sv },
 | |
|         { State::Down | State::Right | State::Frame2, "/res/graphics/catdog/serun2.png"sv },
 | |
|         { State::Down | State::Right, "/res/graphics/catdog/serun1.png"sv },
 | |
|         { State::Down | State::Left | State::Frame2, "/res/graphics/catdog/swrun2.png"sv },
 | |
|         { State::Down | State::Left, "/res/graphics/catdog/swrun1.png"sv },
 | |
|         { State::Up | State::Frame2, "/res/graphics/catdog/nrun2.png"sv },
 | |
|         { State::Up, "/res/graphics/catdog/nrun1.png"sv },
 | |
|         { State::Down | State::Frame2, "/res/graphics/catdog/srun2.png"sv },
 | |
|         { State::Down, "/res/graphics/catdog/srun1.png"sv },
 | |
|         { State::Left | State::Frame2, "/res/graphics/catdog/wrun2.png"sv },
 | |
|         { State::Left, "/res/graphics/catdog/wrun1.png"sv },
 | |
|         { State::Right | State::Frame2, "/res/graphics/catdog/erun2.png"sv },
 | |
|         { State::Right, "/res/graphics/catdog/erun1.png"sv },
 | |
|         { State::Sleeping | State::Frame2, "/res/graphics/catdog/sleep2.png"sv },
 | |
|         { State::Sleeping, "/res/graphics/catdog/sleep1.png"sv },
 | |
|         { State::Idle | State::Artist, "/res/graphics/catdog/artist.png"sv },
 | |
|         { State::Idle | State::Inspector, "/res/graphics/catdog/inspector.png"sv },
 | |
|         { State::Idle, "/res/graphics/catdog/still.png"sv },
 | |
|         { State::Alert | State::Artist, "/res/graphics/catdog/artist.png"sv },
 | |
|         { State::Alert | State::Inspector, "/res/graphics/catdog/inspector.png"sv },
 | |
|         { State::Alert, "/res/graphics/catdog/alert.png"sv }
 | |
|     };
 | |
| 
 | |
|     auto catdog = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) CatDog));
 | |
|     for (auto const& image_source : image_sources)
 | |
|         TRY(catdog->m_images.try_append({ image_source.state, *TRY(Gfx::Bitmap::load_from_file(image_source.path)) }));
 | |
| 
 | |
|     return catdog;
 | |
| }
 | |
| 
 | |
| CatDog::CatDog()
 | |
|     : m_proc_all(MUST(Core::File::open("/sys/kernel/processes"sv, Core::File::OpenMode::Read)))
 | |
| {
 | |
|     m_idle_sleep_timer.start();
 | |
| }
 | |
| 
 | |
| void CatDog::set_roaming(bool roaming)
 | |
| {
 | |
|     m_state = (roaming ? State::Idle : State::Alert) | special_application_states();
 | |
|     update();
 | |
| }
 | |
| 
 | |
| CatDog::State CatDog::special_application_states() const
 | |
| {
 | |
|     auto maybe_proc_info = Core::ProcessStatisticsReader::get_all(*m_proc_all);
 | |
|     if (maybe_proc_info.is_error())
 | |
|         return State::GenericCatDog;
 | |
| 
 | |
|     auto proc_info = maybe_proc_info.release_value();
 | |
|     auto maybe_paint_program = proc_info.processes.first_matching([](auto& process) {
 | |
|         return process.name.equals_ignoring_ascii_case("pixelpaint"sv) || process.name.equals_ignoring_ascii_case("fonteditor"sv);
 | |
|     });
 | |
|     if (maybe_paint_program.has_value())
 | |
|         return State::Artist;
 | |
| 
 | |
|     auto maybe_inspector_program = proc_info.processes.first_matching([](auto& process) {
 | |
|         return process.name.equals_ignoring_ascii_case("systemmonitor"sv) || process.name.equals_ignoring_ascii_case("profiler"sv);
 | |
|     });
 | |
|     if (maybe_inspector_program.has_value())
 | |
|         return State::Inspector;
 | |
| 
 | |
|     return State::GenericCatDog;
 | |
| }
 | |
| 
 | |
| bool CatDog::is_artist() const
 | |
| {
 | |
|     return has_flag(special_application_states(), State::Artist);
 | |
| }
 | |
| 
 | |
| bool CatDog::is_inspector() const
 | |
| {
 | |
|     return has_flag(special_application_states(), State::Inspector);
 | |
| }
 | |
| 
 | |
| void CatDog::timer_event(Core::TimerEvent&)
 | |
| {
 | |
|     using namespace AK::TimeLiterals;
 | |
| 
 | |
|     if (has_flag(m_state, State::Alert))
 | |
|         return;
 | |
| 
 | |
|     m_state = special_application_states();
 | |
| 
 | |
|     auto const size = window()->size();
 | |
|     Gfx::IntPoint move;
 | |
| 
 | |
|     if (m_mouse_offset.x() < 0) {
 | |
|         m_state |= State::Left;
 | |
|         move.set_x(max(m_mouse_offset.x(), -size.width() / 2));
 | |
|     } else if (m_mouse_offset.x() > size.width()) {
 | |
|         m_state |= State::Right;
 | |
|         move.set_x(min(m_mouse_offset.x(), size.width() / 2));
 | |
|     }
 | |
| 
 | |
|     if (m_mouse_offset.y() < 0) {
 | |
|         m_state |= State::Up;
 | |
|         move.set_y(max(m_mouse_offset.y(), -size.height() / 2));
 | |
|     } else if (m_mouse_offset.y() > size.height()) {
 | |
|         m_state |= State::Down;
 | |
|         move.set_y(min(m_mouse_offset.y(), size.height() / 2));
 | |
|     }
 | |
| 
 | |
|     if (has_any_flag(m_state, State::Directions)) {
 | |
|         m_idle_sleep_timer.start();
 | |
|     } else {
 | |
|         if (m_idle_sleep_timer.elapsed_time() > 5_sec)
 | |
|             m_state |= State::Sleeping;
 | |
|         else
 | |
|             m_state |= State::Idle;
 | |
|     }
 | |
| 
 | |
|     window()->move_to(window()->position() + move);
 | |
|     m_mouse_offset -= move;
 | |
| 
 | |
|     m_frame = m_frame == State::Frame1 ? State::Frame2 : State::Frame1;
 | |
|     m_state |= m_frame;
 | |
| 
 | |
|     update();
 | |
| }
 | |
| 
 | |
| Gfx::Bitmap& CatDog::bitmap_for_state() const
 | |
| {
 | |
|     auto const iter = m_images.find_if([&](auto const& image) { return (m_state & image.state) == image.state; });
 | |
|     return iter != m_images.end() ? *iter->bitmap : *m_images[m_images.size() - 1].bitmap;
 | |
| }
 | |
| 
 | |
| void CatDog::paint_event(GUI::PaintEvent& event)
 | |
| {
 | |
|     auto const& bmp = bitmap_for_state();
 | |
|     GUI::Painter painter(*this);
 | |
|     painter.clear_rect(event.rect(), Gfx::Color());
 | |
|     painter.blit(Gfx::IntPoint(0, 0), bmp, bmp.rect());
 | |
| }
 | |
| 
 | |
| void CatDog::track_mouse_move(Gfx::IntPoint point)
 | |
| {
 | |
|     if (has_flag(m_state, State::Alert))
 | |
|         return;
 | |
| 
 | |
|     Gfx::IntPoint relative_offset = point - window()->position();
 | |
|     if (m_mouse_offset != relative_offset) {
 | |
|         m_mouse_offset = relative_offset;
 | |
|         m_idle_sleep_timer.start();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CatDog::mousedown_event(GUI::MouseEvent& event)
 | |
| {
 | |
|     if (event.button() == GUI::MouseButton::Primary && on_click)
 | |
|         on_click();
 | |
| }
 | |
| 
 | |
| void CatDog::context_menu_event(GUI::ContextMenuEvent& event)
 | |
| {
 | |
|     if (on_context_menu_request)
 | |
|         on_context_menu_request(event);
 | |
| }
 |