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 "WindowsView.h" 8 9 #include <stdlib.h> 10 11 #include <LayoutBuilder.h> 12 #include <ObjectList.h> 13 #include <StringView.h> 14 15 #include <MessengerPrivate.h> 16 #include <WindowInfo.h> 17 #include <WindowPrivate.h> 18 19 #include "GroupListView.h" 20 #include "LaunchButton.h" 21 #include "Switcher.h" 22 23 24 static const uint32 kMsgActivateWindow = 'AcWn'; 25 26 27 class WindowModel : public GroupListModel { 28 public: 29 WindowModel(team_id team) 30 : 31 fWindows(true), 32 fWorkspaces(0), 33 fWorkspaceCount(0) 34 { 35 // TODO: more than one team via signature! 36 int32 count; 37 int32* tokens = get_token_list(team, &count); 38 39 for (int32 i = 0; i < count; i++) { 40 client_window_info* info = get_window_info(tokens[i]); 41 if (!_WindowShouldBeListed(info)) { 42 free(info); 43 continue; 44 } 45 46 fWorkspaces |= info->workspaces; 47 fWindows.AddItem(info); 48 } 49 free(tokens); 50 51 for (uint32 i = 0; i < 32; i++) { 52 if ((fWorkspaces & (1UL << i)) != 0) 53 fWorkspaceCount++; 54 } 55 56 fWindows.SortItems(&_CompareWindowInfo); 57 } 58 59 virtual ~WindowModel() 60 { 61 } 62 63 void BringToFront(int32 index) 64 { 65 client_window_info* info = fWindows.ItemAt(index); 66 if (info == NULL) 67 return; 68 69 do_window_action(info->server_token, B_BRING_TO_FRONT, BRect(), false); 70 } 71 72 void Close(int32 index) 73 { 74 client_window_info* info = fWindows.ItemAt(index); 75 if (info == NULL) 76 return; 77 78 BMessenger window; 79 BMessenger::Private(window).SetTo(info->team, info->client_port, 80 info->client_token); 81 window.SendMessage(B_QUIT_REQUESTED); 82 } 83 84 virtual int32 CountItems() 85 { 86 return fWindows.CountItems(); 87 } 88 89 virtual void* ItemAt(int32 index) 90 { 91 return fWindows.ItemAt(index); 92 } 93 94 virtual int32 CountGroups() 95 { 96 return fWorkspaceCount; 97 } 98 99 virtual addr_t GroupAt(int32 index) 100 { 101 return _NthSetBit(index, fWorkspaces) + 1; 102 } 103 104 virtual addr_t GroupForItemAt(int32 index) 105 { 106 client_window_info* info = fWindows.ItemAt(index); 107 return _NthSetBit(0, info->workspaces) + 1; 108 } 109 110 private: 111 bool _WindowShouldBeListed(client_window_info* info) 112 { 113 return info != NULL 114 && (info->feel == B_NORMAL_WINDOW_FEEL 115 || info->feel == kWindowScreenFeel) 116 && (info->show_hide_level <= 0 || info->is_mini); 117 } 118 119 uint32 _NthSetBit(int32 index, uint32 mask) 120 { 121 for (uint32 i = 0; i < 32; i++) { 122 if ((mask & (1UL << i)) != 0) { 123 if (index-- == 0) 124 return i; 125 } 126 } 127 return 0; 128 } 129 130 static int _CompareWindowInfo(const client_window_info* a, 131 const client_window_info* b) 132 { 133 return strcasecmp(a->name, b->name); 134 } 135 136 private: 137 BObjectList<client_window_info> fWindows; 138 uint32 fWorkspaces; 139 int32 fWorkspaceCount; 140 }; 141 142 143 class StringItemRenderer : public ListItemRenderer { 144 public: 145 StringItemRenderer() 146 { 147 } 148 149 virtual ~StringItemRenderer() 150 { 151 } 152 153 void SetText(BView* owner, const BString& text) 154 { 155 fText = text; 156 owner->TruncateString(&fText, B_TRUNCATE_MIDDLE, 200); 157 SetWidth((int32)ceilf(owner->StringWidth(fText.String()))); 158 159 font_height fontHeight; 160 owner->GetFontHeight(&fontHeight); 161 162 SetBaselineOffset( 163 2 + (int32)ceilf(fontHeight.ascent + fontHeight.leading / 2)); 164 165 SetHeight((int32)ceilf(fontHeight.ascent) 166 + (int32)ceilf(fontHeight.descent) 167 + (int32)ceilf(fontHeight.leading) + 4); 168 } 169 170 virtual void SetWidth(int32 width) 171 { 172 fWidth = width; 173 } 174 175 virtual void SetHeight(int32 height) 176 { 177 fHeight = height; 178 } 179 180 virtual void SetBaselineOffset(int32 offset) 181 { 182 fBaselineOffset = offset; 183 } 184 185 const BString& Text() const 186 { 187 return fText; 188 } 189 190 virtual BSize MinSize() 191 { 192 return BSize(fWidth, fHeight); 193 } 194 195 virtual BSize MaxSize() 196 { 197 return BSize(B_SIZE_UNLIMITED, fHeight); 198 } 199 200 virtual BSize PreferredSize() 201 { 202 return BSize(fWidth, fHeight); 203 } 204 205 virtual void Draw(BView* owner, BRect frame, int32 index, bool selected) 206 { 207 owner->SetLowColor(owner->ViewColor()); 208 owner->MovePenTo(frame.left, frame.top + fBaselineOffset); 209 owner->DrawString(fText); 210 } 211 212 private: 213 BString fText; 214 int32 fWidth; 215 int32 fHeight; 216 int32 fBaselineOffset; 217 }; 218 219 220 class WorkspaceRenderer : public StringItemRenderer { 221 public: 222 virtual void SetTo(BView* owner, void* item) 223 { 224 fWorkspace = (uintptr_t)item; 225 226 if ((uint32)current_workspace() == fWorkspace - 1) 227 SetText(owner, "Current workspace"); 228 else { 229 BString text("Workspace "); 230 text << fWorkspace; 231 SetText(owner, text); 232 } 233 } 234 235 virtual void Draw(BView* owner, BRect frame, int32 index, bool selected) 236 { 237 owner->SetHighColor(tint_color(owner->ViewColor(), B_DARKEN_2_TINT)); 238 StringItemRenderer::Draw(owner, frame, index, false); 239 } 240 241 private: 242 uint32 fWorkspace; 243 }; 244 245 246 class WindowRenderer : public StringItemRenderer { 247 public: 248 virtual void SetTo(BView* owner, void* item) 249 { 250 fInfo = (client_window_info*)item; 251 SetText(owner, fInfo->name); 252 } 253 254 virtual void SetWidth(int32 width) 255 { 256 StringItemRenderer::SetWidth(width + 20); 257 } 258 259 virtual void Draw(BView* owner, BRect frame, int32 index, bool selected) 260 { 261 owner->SetHighColor(0, 0, 0); 262 frame.left += 20; 263 StringItemRenderer::Draw(owner, frame, index, selected); 264 } 265 266 private: 267 client_window_info* fInfo; 268 }; 269 270 271 // #pragma mark - 272 273 274 WindowsView::WindowsView(team_id team, uint32 location) 275 : 276 BGridView("windows") 277 { 278 app_info info; 279 be_roster->GetRunningAppInfo(team, &info); 280 281 LaunchButton* launchButton = new LaunchButton(info.signature, NULL, NULL, 282 this); 283 launchButton->SetTo(&info.ref); 284 285 BStringView* nameView = new BStringView("name", info.ref.name); 286 BFont font(be_plain_font); 287 font.SetSize(font.Size() * 2); 288 font.SetFace(B_BOLD_FACE); 289 nameView->SetFont(&font); 290 291 fListView = new GroupListView("list", new WindowModel(team), 292 _Orientation(location)); 293 fListView->SetItemRenderer(new WindowRenderer()); 294 fListView->SetGroupRenderer(new WorkspaceRenderer()); 295 296 GridLayout()->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 297 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); 298 299 if (_Orientation(location) == B_HORIZONTAL) { 300 BLayoutBuilder::Grid<>(this) 301 .Add(launchButton, 0, 0) 302 .Add(nameView, 1, 0) 303 .Add(fListView, 2, 0); 304 } else { 305 BLayoutBuilder::Grid<>(this) 306 .Add(launchButton, 0, 0) 307 .Add(nameView, 1, 0) 308 .Add(fListView, 0, 1, 2); 309 } 310 } 311 312 313 WindowsView::~WindowsView() 314 { 315 } 316 317 318 void 319 WindowsView::AttachedToWindow() 320 { 321 fListView->SetSelectionMessage(new BMessage(kMsgActivateWindow), this); 322 } 323 324 325 void 326 WindowsView::MessageReceived(BMessage* message) 327 { 328 switch (message->what) { 329 case kMsgActivateWindow: 330 { 331 int32 index; 332 if (message->FindInt32("index", &index) == B_OK 333 && message->HasPointer("item")) { 334 WindowModel* model = (WindowModel*)fListView->Model(); 335 336 if (message->FindInt32("buttons") == B_SECONDARY_MOUSE_BUTTON) 337 model->Close(index); 338 else 339 model->BringToFront(index); 340 } 341 break; 342 } 343 344 default: 345 BGridView::MessageReceived(message); 346 break; 347 } 348 } 349 350 351 orientation 352 WindowsView::_Orientation(uint32 location) 353 { 354 return (location & (kTopEdge | kBottomEdge)) != 0 355 ? B_HORIZONTAL : B_VERTICAL; 356 } 357