xref: /haiku/src/apps/switcher/CaptureWindow.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "CaptureWindow.h"
8 
9 #include <stdio.h>
10 
11 #include <Roster.h>
12 #include <Screen.h>
13 
14 #include "Switcher.h"
15 
16 
17 static const bigtime_t kUpdateDelay = 50000;
18 	// 50 ms
19 
20 
21 class CaptureView : public BView {
22 public:
23 								CaptureView();
24 	virtual						~CaptureView();
25 
26 			void				AddMoveOutNotification(BMessage* message);
27 
28 	virtual	void				MouseMoved(BPoint point, uint32 transit,
29 									const BMessage* dragMessage);
30 	virtual void				KeyDown(const char* bytes, int32 numBytes);
31 
32 private:
33 			void				_UpdateLast(const BPoint& point);
34 			void				_Notify(uint32 location, team_id team);
35 			void				_SendMovedOutNotification();
36 
37 	static	team_id				_CurrentTeam();
38 
39 private:
40 			uint32				fModifierMask;
41 			BPoint				fLastPoint;
42 			team_id				fLastTeam;
43 			bigtime_t			fLastEvent;
44 
45 			uint32				fMovedOutWhat;
46 			BMessenger			fMovedOutMessenger;
47 			BRect				fMovedOutFrame;
48 };
49 
50 
51 CaptureView::CaptureView()
52 	:
53 	BView("main", 0),
54 	fModifierMask(B_CONTROL_KEY),
55 	fMovedOutWhat(0)
56 {
57 	SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, B_NO_POINTER_HISTORY);
58 	_UpdateLast(BPoint(-1, -1));
59 }
60 
61 
62 CaptureView::~CaptureView()
63 {
64 }
65 
66 
67 void
68 CaptureView::AddMoveOutNotification(BMessage* message)
69 {
70 	if (fMovedOutWhat != 0)
71 		_SendMovedOutNotification();
72 
73 	if (message->FindMessenger("target", &fMovedOutMessenger) == B_OK
74 		&& message->FindRect("frame", &fMovedOutFrame) == B_OK)
75 		fMovedOutWhat = (uint32)message->FindInt32("what");
76 }
77 
78 
79 void
80 CaptureView::MouseMoved(BPoint point, uint32 transit,
81 	const BMessage* dragMessage)
82 {
83 	ConvertToScreen(&point);
84 
85 	if (fMovedOutWhat != 0 && !fMovedOutFrame.Contains(point))
86 		_SendMovedOutNotification();
87 
88 	uint32 modifiers = ::modifiers();
89 	if ((modifiers & fModifierMask) == 0) {
90 		_UpdateLast(point);
91 		return;
92 	}
93 
94 	// TODO: we will need to iterate over all existing screens to find the
95 	// right one!
96 	BScreen screen;
97 	BRect screenFrame = screen.Frame();
98 
99 	uint32 location = kNowhere;
100 	if (point.x <= screenFrame.left && fLastPoint.x > screenFrame.left)
101 		location = kLeftEdge;
102 	else if (point.x >= screenFrame.right && fLastPoint.x < screenFrame.right)
103 		location = kRightEdge;
104 	else if (point.y <= screenFrame.top && fLastPoint.y > screenFrame.top)
105 		location = kTopEdge;
106 	else if (point.y >= screenFrame.bottom && fLastPoint.y < screenFrame.bottom)
107 		location = kBottomEdge;
108 
109 	if (location != kNowhere)
110 		_Notify(location, fLastTeam);
111 
112 	_UpdateLast(point);
113 }
114 
115 
116 void
117 CaptureView::KeyDown(const char* bytes, int32 numBytes)
118 {
119 	if ((::modifiers() & (B_CONTROL_KEY | B_SHIFT_KEY | B_OPTION_KEY
120 			| B_COMMAND_KEY)) != (B_COMMAND_KEY | B_CONTROL_KEY))
121 		return;
122 
123 	uint32 location = kNowhere;
124 
125 	switch (bytes[0]) {
126 		case '1':
127 			location = kLeftEdge;
128 			break;
129 		case '2':
130 			location = kRightEdge;
131 			break;
132 		case '3':
133 			location = kTopEdge;
134 			break;
135 		case '4':
136 			location = kBottomEdge;
137 			break;
138 	}
139 
140 	if (location != kNowhere)
141 		_Notify(location, _CurrentTeam());
142 }
143 
144 
145 void
146 CaptureView::_UpdateLast(const BPoint& point)
147 {
148 	fLastPoint = point;
149 
150 	bigtime_t now = system_time();
151 
152 	// We update the currently active application only, if the mouse did
153 	// not move over it for a certain time - this is necessary only for
154 	// focus follow mouse.
155 	if (now > fLastEvent + kUpdateDelay)
156 		fLastTeam = _CurrentTeam();
157 
158 	fLastEvent = now;
159 }
160 
161 
162 void
163 CaptureView::_Notify(uint32 location, team_id team)
164 {
165 	if (location == kNowhere)
166 		return;
167 
168 	BMessage message(kMsgLocationTrigger);
169 	message.AddInt32("location", location);
170 	message.AddInt32("team", team);
171 
172 	be_app->PostMessage(&message);
173 }
174 
175 
176 void
177 CaptureView::_SendMovedOutNotification()
178 {
179 	BMessage movedOut(fMovedOutWhat);
180 	fMovedOutMessenger.SendMessage(&movedOut);
181 	fMovedOutWhat = 0;
182 }
183 
184 
185 /*static*/ team_id
186 CaptureView::_CurrentTeam()
187 {
188 	app_info appInfo;
189 	status_t status = be_roster->GetActiveAppInfo(&appInfo);
190 	if (status == B_OK)
191 		return appInfo.team;
192 
193 	return status;
194 }
195 
196 
197 // #pragma mark -
198 
199 
200 CaptureWindow::CaptureWindow()
201 	:
202 	BWindow(BRect(0, 0, 100, 100), "mouse capture", B_NO_BORDER_WINDOW_LOOK,
203 		B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES)
204 {
205 	fCaptureView = new CaptureView();
206 	AddChild(fCaptureView);
207 }
208 
209 
210 CaptureWindow::~CaptureWindow()
211 {
212 }
213 
214 
215 void
216 CaptureWindow::MessageReceived(BMessage* message)
217 {
218 	switch (message->what) {
219 		case kMsgHideWhenMouseMovedOut:
220 			fCaptureView->AddMoveOutNotification(message);
221 			break;
222 		default:
223 			BWindow::MessageReceived(message);
224 			break;
225 	}
226 }
227