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