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
CaptureView()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
~CaptureView()62 CaptureView::~CaptureView()
63 {
64 }
65
66
67 void
AddMoveOutNotification(BMessage * message)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
MouseMoved(BPoint point,uint32 transit,const BMessage * dragMessage)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
KeyDown(const char * bytes,int32 numBytes)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
_UpdateLast(const BPoint & point)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
_Notify(uint32 location,team_id team)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
_SendMovedOutNotification()177 CaptureView::_SendMovedOutNotification()
178 {
179 BMessage movedOut(fMovedOutWhat);
180 fMovedOutMessenger.SendMessage(&movedOut);
181 fMovedOutWhat = 0;
182 }
183
184
185 /*static*/ team_id
_CurrentTeam()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
CaptureWindow()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
~CaptureWindow()210 CaptureWindow::~CaptureWindow()
211 {
212 }
213
214
215 void
MessageReceived(BMessage * message)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