xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision ffcd67bc8277349aebf089d7357716698aafd55b)
1 /*
2  * Copyright 2001-2006, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Caz <turok2@currantbun.com>
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 /**	Global functions and variables for the Interface Kit */
12 
13 #include <interface_misc.h>
14 #include <truncate_string.h>
15 #include <utf8_functions.h>
16 
17 #include <ApplicationPrivate.h>
18 #include <AppServerLink.h>
19 #include <DefaultColors.h>
20 #include <InputServerTypes.h>
21 #include <input_globals.h>
22 #include <ServerProtocol.h>
23 #include <ServerReadOnlyMemory.h>
24 #include <WidthBuffer.h>
25 #include <WindowInfo.h>
26 
27 #include <Font.h>
28 #include <InterfaceDefs.h>
29 #include <Menu.h>
30 #include <Roster.h>
31 #include <ScrollBar.h>
32 #include <Screen.h>
33 #include <String.h>
34 #include <TextView.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 
41 // Private definitions not placed in public headers
42 void _init_global_fonts_();
43 extern "C" status_t _fini_interface_kit_();
44 
45 using namespace BPrivate;
46 
47 // some other weird struct exported by BeOS, it's not initialized, though
48 struct general_ui_info {
49 	rgb_color	background_color;
50 	rgb_color	mark_color;
51 	rgb_color	highlight_color;
52 	bool		color_frame;
53 	rgb_color	window_frame_color;
54 };
55 
56 struct general_ui_info general_info;
57 
58 menu_info *_menu_info_ptr_;
59 
60 extern "C" const char B_NOTIFICATION_SENDER[] = "be:sender";
61 
62 static const rgb_color _kDefaultColors[kNumColors] = {
63 	{216, 216, 216, 255},	// B_PANEL_BACKGROUND_COLOR
64 	{216, 216, 216, 255},	// B_MENU_BACKGROUND_COLOR
65 	{255, 203, 0, 255},		// B_WINDOW_TAB_COLOR
66 	{0, 0, 229, 255},		// B_KEYBOARD_NAVIGATION_COLOR
67 	{51, 102, 152, 255},	// B_DESKTOP_COLOR
68 	{153, 153, 153, 255},	// B_MENU_SELECTED_BACKGROUND_COLOR
69 	{0, 0, 0, 255},			// B_MENU_ITEM_TEXT_COLOR
70 	{0, 0, 0, 255},			// B_MENU_SELECTED_ITEM_TEXT_COLOR
71 	{0, 0, 0, 255},			// B_MENU_SELECTED_BORDER_COLOR
72 	{0, 0, 0, 255},			// B_PANEL_TEXT_COLOR
73 	{255, 255, 255, 255},	// B_DOCUMENT_BACKGROUND_COLOR
74 	{0, 0, 0, 255},			// B_DOCUMENT_TEXT_COLOR
75 	{245, 245, 245, 255},	// B_CONTROL_BACKGROUND_COLOR
76 	{0, 0, 0, 255},			// B_CONTROL_TEXT_COLOR
77 	{0, 0, 0, 255},			// B_CONTROL_BORDER_COLOR
78 	{102, 152, 203, 255},	// B_CONTROL_HIGHLIGHT_COLOR
79 	{0, 0, 0, 255},			// B_NAVIGATION_PULSE_COLOR
80 	{255, 255, 255, 255},	// B_SHINE_COLOR
81 	{0, 0, 0, 255},			// B_SHADOW_COLOR
82 	{255, 255, 0, 255},		// B_TOOLTIP_BACKGROUND_COLOR
83 	{0, 0, 0, 255},			// B_TOOLTIP_TEXT_COLOR
84 	{0, 0, 0, 255},			// B_WINDOW_TEXT_COLOR
85 	{232, 232, 232, 255},	// B_WINDOW_INACTIVE_TAB_COLOR
86 	{80, 80, 80, 255},		// B_WINDOW_INACTIVE_TEXT_COLOR
87 	// 100...
88 	{0, 255, 0, 255},		// B_SUCCESS_COLOR
89 	{255, 0, 0, 255},		// B_FAILURE_COLOR
90 	{}
91 };
92 const rgb_color* BPrivate::kDefaultColors = &_kDefaultColors[0];
93 
94 
95 /*!
96 	Fills the \a width, \a height, and \a colorSpace parameters according
97 	to the window screen's mode.
98 	Returns \c true if the mode is known.
99 */
100 bool
101 get_mode_parameter(uint32 mode, int32& width, int32& height, uint32& colorSpace)
102 {
103 	switch (mode) {
104 		case B_8_BIT_640x480:
105 		case B_8_BIT_800x600:
106 		case B_8_BIT_1024x768:
107    		case B_8_BIT_1152x900:
108 		case B_8_BIT_1280x1024:
109 		case B_8_BIT_1600x1200:
110 			colorSpace = B_CMAP8;
111 			break;
112 
113 		case B_15_BIT_640x480:
114 		case B_15_BIT_800x600:
115 		case B_15_BIT_1024x768:
116    		case B_15_BIT_1152x900:
117 		case B_15_BIT_1280x1024:
118 		case B_15_BIT_1600x1200:
119    			colorSpace = B_RGB15;
120    			break;
121 
122 		case B_16_BIT_640x480:
123 		case B_16_BIT_800x600:
124 		case B_16_BIT_1024x768:
125    		case B_16_BIT_1152x900:
126 		case B_16_BIT_1280x1024:
127 		case B_16_BIT_1600x1200:
128 			colorSpace = B_RGB16;
129 			break;
130 
131 		case B_32_BIT_640x480:
132 		case B_32_BIT_800x600:
133 		case B_32_BIT_1024x768:
134    		case B_32_BIT_1152x900:
135 		case B_32_BIT_1280x1024:
136 		case B_32_BIT_1600x1200:
137 			colorSpace = B_RGB32;
138 			break;
139 
140 		default:
141 			return false;
142 	}
143 
144 	switch (mode) {
145 		case B_8_BIT_640x480:
146 		case B_15_BIT_640x480:
147 		case B_16_BIT_640x480:
148 		case B_32_BIT_640x480:
149 			width = 640; height = 480;
150 			break;
151 
152 		case B_8_BIT_800x600:
153 		case B_15_BIT_800x600:
154 		case B_16_BIT_800x600:
155 		case B_32_BIT_800x600:
156 			width = 800; height = 600;
157 			break;
158 
159 		case B_8_BIT_1024x768:
160 		case B_15_BIT_1024x768:
161 		case B_16_BIT_1024x768:
162 		case B_32_BIT_1024x768:
163 			width = 1024; height = 768;
164 			break;
165 
166    		case B_8_BIT_1152x900:
167    		case B_15_BIT_1152x900:
168    		case B_16_BIT_1152x900:
169    		case B_32_BIT_1152x900:
170    			width = 1152; height = 900;
171    			break;
172 
173 		case B_8_BIT_1280x1024:
174 		case B_15_BIT_1280x1024:
175 		case B_16_BIT_1280x1024:
176 		case B_32_BIT_1280x1024:
177 			width = 1280; height = 1024;
178 			break;
179 
180 		case B_8_BIT_1600x1200:
181 		case B_15_BIT_1600x1200:
182 		case B_16_BIT_1600x1200:
183 		case B_32_BIT_1600x1200:
184 			width = 1600; height = 1200;
185 			break;
186 	}
187 
188 	return true;
189 }
190 
191 
192 _IMPEXP_BE const color_map *
193 system_colors()
194 {
195 	return BScreen(B_MAIN_SCREEN_ID).ColorMap();
196 }
197 
198 
199 _IMPEXP_BE status_t
200 set_screen_space(int32 index, uint32 space, bool stick)
201 {
202 	int32 width;
203 	int32 height;
204 	uint32 depth;
205 	if (!get_mode_parameter(space, width, height, depth))
206 		return B_BAD_VALUE;
207 
208 	BScreen screen(B_MAIN_SCREEN_ID);
209 	display_mode mode;
210 
211 	// TODO: What about refresh rate ?
212 	// currently we get it from the current video mode, but
213 	// this might be not so wise.
214 	status_t status = screen.GetMode(index, &mode);
215 	if (status < B_OK)
216 		return status;
217 
218 	mode.virtual_width = width;
219 	mode.virtual_height = height;
220 	mode.space = depth;
221 
222 	return screen.SetMode(index, &mode, stick);
223 }
224 
225 
226 _IMPEXP_BE status_t
227 get_scroll_bar_info(scroll_bar_info *info)
228 {
229 	if (info == NULL)
230 		return B_BAD_VALUE;
231 
232 	BPrivate::AppServerLink link;
233 	link.StartMessage(AS_GET_SCROLLBAR_INFO);
234 
235 	int32 code;
236 	if (link.FlushWithReply(code) == B_OK
237 		&& code == B_OK) {
238 		link.Read<scroll_bar_info>(info);
239 		return B_OK;
240 	}
241 
242 	return B_ERROR;
243 }
244 
245 
246 _IMPEXP_BE status_t
247 set_scroll_bar_info(scroll_bar_info *info)
248 {
249 	if (info == NULL)
250 		return B_BAD_VALUE;
251 
252 	BPrivate::AppServerLink link;
253 	int32 code;
254 
255 	link.StartMessage(AS_SET_SCROLLBAR_INFO);
256 	link.Attach<scroll_bar_info>(*info);
257 
258 	if (link.FlushWithReply(code) == B_OK
259 		&& code == B_OK)
260 		return B_OK;
261 
262 	return B_ERROR;
263 }
264 
265 
266 _IMPEXP_BE status_t
267 get_mouse_type(int32 *type)
268 {
269 	BMessage command(IS_GET_MOUSE_TYPE);
270 	BMessage reply;
271 
272 	_control_input_server_(&command, &reply);
273 
274 	if(reply.FindInt32("mouse_type", type) != B_OK)
275 		return B_ERROR;
276 
277 	return B_OK;
278 }
279 
280 
281 _IMPEXP_BE status_t
282 set_mouse_type(int32 type)
283 {
284 	BMessage command(IS_SET_MOUSE_TYPE);
285 	BMessage reply;
286 
287 	command.AddInt32("mouse_type", type);
288 	return _control_input_server_(&command, &reply);
289 }
290 
291 
292 _IMPEXP_BE status_t
293 get_mouse_map(mouse_map *map)
294 {
295 	BMessage command(IS_GET_MOUSE_MAP);
296 	BMessage reply;
297 	const void *data = 0;
298 	ssize_t count;
299 
300 	_control_input_server_(&command, &reply);
301 
302 	if (reply.FindData("mousemap", B_RAW_TYPE, &data, &count) != B_OK)
303 		return B_ERROR;
304 
305 	memcpy(map, data, count);
306 
307 	return B_OK;
308 }
309 
310 
311 _IMPEXP_BE status_t
312 set_mouse_map(mouse_map *map)
313 {
314 	BMessage command(IS_SET_MOUSE_MAP);
315 	BMessage reply;
316 
317 	command.AddData("mousemap", B_RAW_TYPE, map, sizeof(mouse_map));
318 	return _control_input_server_(&command, &reply);
319 }
320 
321 
322 _IMPEXP_BE status_t
323 get_click_speed(bigtime_t *speed)
324 {
325 	BMessage command(IS_GET_CLICK_SPEED);
326 	BMessage reply;
327 
328 	_control_input_server_(&command, &reply);
329 
330 	if (reply.FindInt64("speed", speed) != B_OK)
331 		*speed = 500000;
332 
333 	return B_OK;
334 }
335 
336 
337 _IMPEXP_BE status_t
338 set_click_speed(bigtime_t speed)
339 {
340 	BMessage command(IS_SET_CLICK_SPEED);
341 	BMessage reply;
342 	command.AddInt64("speed", speed);
343 	return _control_input_server_(&command, &reply);
344 }
345 
346 
347 _IMPEXP_BE status_t
348 get_mouse_speed(int32 *speed)
349 {
350 	BMessage command(IS_GET_MOUSE_SPEED);
351 	BMessage reply;
352 
353 	_control_input_server_(&command, &reply);
354 
355 	if (reply.FindInt32("speed", speed) != B_OK)
356 		*speed = 65536;
357 
358 	return B_OK;
359 }
360 
361 
362 _IMPEXP_BE status_t
363 set_mouse_speed(int32 speed)
364 {
365 	BMessage command(IS_SET_MOUSE_SPEED);
366 	BMessage reply;
367 	command.AddInt32("speed", speed);
368 	return _control_input_server_(&command, &reply);
369 }
370 
371 
372 _IMPEXP_BE status_t
373 get_mouse_acceleration(int32 *speed)
374 {
375 	BMessage command(IS_GET_MOUSE_ACCELERATION);
376 	BMessage reply;
377 
378 	_control_input_server_(&command, &reply);
379 
380 	if (reply.FindInt32("speed", speed) != B_OK)
381 		*speed = 65536;
382 
383 	return B_OK;
384 }
385 
386 
387 _IMPEXP_BE status_t
388 set_mouse_acceleration(int32 speed)
389 {
390 	BMessage command(IS_SET_MOUSE_ACCELERATION);
391 	BMessage reply;
392 	command.AddInt32("speed", speed);
393 	return _control_input_server_(&command, &reply);
394 }
395 
396 
397 _IMPEXP_BE status_t
398 get_key_repeat_rate(int32 *rate)
399 {
400 	BMessage command(IS_GET_KEY_REPEAT_RATE);
401 	BMessage reply;
402 
403 	_control_input_server_(&command, &reply);
404 
405 	if (reply.FindInt32("rate", rate) != B_OK)
406 		*rate = 250000;
407 
408 	return B_OK;
409 }
410 
411 
412 _IMPEXP_BE status_t
413 set_key_repeat_rate(int32 rate)
414 {
415 	BMessage command(IS_SET_KEY_REPEAT_RATE);
416 	BMessage reply;
417 	command.AddInt32("rate", rate);
418 	return _control_input_server_(&command, &reply);
419 }
420 
421 
422 _IMPEXP_BE status_t
423 get_key_repeat_delay(bigtime_t *delay)
424 {
425 	BMessage command(IS_GET_KEY_REPEAT_DELAY);
426 	BMessage reply;
427 
428 	_control_input_server_(&command, &reply);
429 
430 	if (reply.FindInt64("delay", delay) != B_OK)
431 		*delay = 200;
432 
433 	return B_OK;
434 }
435 
436 
437 _IMPEXP_BE status_t
438 set_key_repeat_delay(bigtime_t  delay)
439 {
440 	BMessage command(IS_SET_KEY_REPEAT_DELAY);
441 	BMessage reply;
442 	command.AddInt64("delay", delay);
443 	return _control_input_server_(&command, &reply);
444 }
445 
446 
447 _IMPEXP_BE uint32
448 modifiers()
449 {
450 	BMessage command(IS_GET_MODIFIERS);
451 	BMessage reply;
452 	int32 err, modifier;
453 
454 	_control_input_server_(&command, &reply);
455 
456 	if (reply.FindInt32("status", &err) != B_OK)
457 		return 0;
458 
459 	if (reply.FindInt32("modifiers", &modifier) != B_OK)
460 		return 0;
461 
462 	return modifier;
463 }
464 
465 
466 _IMPEXP_BE status_t
467 get_key_info(key_info *info)
468 {
469 	BMessage command(IS_GET_KEY_INFO);
470 	BMessage reply;
471 	const void *data = 0;
472 	int32 err;
473 	ssize_t count;
474 
475 	_control_input_server_(&command, &reply);
476 
477 	if (reply.FindInt32("status", &err) != B_OK)
478 		return B_ERROR;
479 
480 	if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK)
481 		return B_ERROR;
482 
483 	memcpy(info, data, count);
484 	return B_OK;
485 }
486 
487 
488 _IMPEXP_BE void
489 get_key_map(key_map **map, char **key_buffer)
490 {
491 	_get_key_map(map, key_buffer, NULL);
492 }
493 
494 
495 _IMPEXP_BE void
496 _get_key_map(key_map **map, char **key_buffer, ssize_t *key_buffer_size)
497 {
498 	BMessage command(IS_GET_KEY_MAP);
499 	BMessage reply;
500 	ssize_t map_count, key_count;
501 	const void *map_array = 0, *key_array = 0;
502 	if (key_buffer_size == NULL)
503 		key_buffer_size = &key_count;
504 
505 	_control_input_server_(&command, &reply);
506 
507 	if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) {
508 		*map = 0; *key_buffer = 0;
509 		return;
510 	}
511 
512 	if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, key_buffer_size) != B_OK) {
513 		*map = 0; *key_buffer = 0;
514 		return;
515 	}
516 
517 	*map = (key_map *)malloc(map_count);
518 	memcpy(*map, map_array, map_count);
519 	*key_buffer = (char *)malloc(*key_buffer_size);
520 	memcpy(*key_buffer, key_array, *key_buffer_size);
521 }
522 
523 
524 _IMPEXP_BE status_t
525 get_keyboard_id(uint16 *id)
526 {
527 	BMessage command(IS_GET_KEYBOARD_ID);
528 	BMessage reply;
529 	uint16 kid;
530 
531 	_control_input_server_(&command, &reply);
532 
533 	reply.FindInt16("id", (int16 *)&kid);
534 	*id = kid;
535 
536 	return B_OK;
537 }
538 
539 
540 _IMPEXP_BE void
541 set_modifier_key(uint32 modifier, uint32 key)
542 {
543 	BMessage command(IS_SET_MODIFIER_KEY);
544 	BMessage reply;
545 
546 	command.AddInt32("modifier", modifier);
547 	command.AddInt32("key", key);
548 	_control_input_server_(&command, &reply);
549 }
550 
551 
552 _IMPEXP_BE void
553 set_keyboard_locks(uint32 modifiers)
554 {
555 	BMessage command(IS_SET_KEYBOARD_LOCKS);
556 	BMessage reply;
557 
558 	command.AddInt32("locks", modifiers);
559 	_control_input_server_(&command, &reply);
560 }
561 
562 
563 _IMPEXP_BE status_t
564 _restore_key_map_()
565 {
566 	BMessage message(IS_RESTORE_KEY_MAP);
567 	BMessage reply;
568 
569 	return _control_input_server_(&message, &reply);
570 }
571 
572 
573 _IMPEXP_BE rgb_color
574 keyboard_navigation_color()
575 {
576 	// Queries the app_server
577 	return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
578 }
579 
580 
581 _IMPEXP_BE int32
582 count_workspaces()
583 {
584 	int32 count = 1;
585 
586 	BPrivate::AppServerLink link;
587 	link.StartMessage(AS_COUNT_WORKSPACES);
588 
589 	status_t status;
590 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
591 		link.Read<int32>(&count);
592 
593 	return count;
594 }
595 
596 
597 _IMPEXP_BE void
598 set_workspace_count(int32 count)
599 {
600 	BPrivate::AppServerLink link;
601 	link.StartMessage(AS_SET_WORKSPACE_COUNT);
602 	link.Attach<int32>(count);
603 	link.Flush();
604 }
605 
606 
607 _IMPEXP_BE int32
608 current_workspace()
609 {
610 	int32 index = 0;
611 
612 	BPrivate::AppServerLink link;
613 	link.StartMessage(AS_CURRENT_WORKSPACE);
614 
615 	int32 status;
616 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
617 		link.Read<int32>(&index);
618 
619 	return index;
620 }
621 
622 
623 _IMPEXP_BE void
624 activate_workspace(int32 workspace)
625 {
626 	BPrivate::AppServerLink link;
627 	link.StartMessage(AS_ACTIVATE_WORKSPACE);
628 	link.Attach<int32>(workspace);
629 	link.Flush();
630 }
631 
632 
633 _IMPEXP_BE bigtime_t
634 idle_time()
635 {
636 	bigtime_t idletime = 0;
637 
638 	BPrivate::AppServerLink link;
639 	link.StartMessage(AS_IDLE_TIME);
640 
641 	int32 code;
642 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
643 		link.Read<int64>(&idletime);
644 
645 	return idletime;
646 }
647 
648 
649 _IMPEXP_BE void
650 run_select_printer_panel()
651 {
652 	// Launches the Printer prefs app via the Roster
653 	be_roster->Launch("application/x-vnd.Be-PRNT");
654 }
655 
656 
657 _IMPEXP_BE void
658 run_add_printer_panel()
659 {
660 	// Launches the Printer prefs app via the Roster and asks it to
661 	// add a printer
662 	// TODO: Implement
663 }
664 
665 
666 _IMPEXP_BE void
667 run_be_about()
668 {
669 	if (be_roster != NULL)
670 		be_roster->Launch("application/x-vnd.Haiku-About");
671 }
672 
673 
674 _IMPEXP_BE void
675 set_focus_follows_mouse(bool follow)
676 {
677 	// obviously deprecated API
678 	set_mouse_mode(B_WARP_MOUSE);
679 }
680 
681 
682 _IMPEXP_BE bool
683 focus_follows_mouse()
684 {
685 	return mouse_mode() != B_NORMAL_MOUSE;
686 }
687 
688 
689 _IMPEXP_BE void
690 set_mouse_mode(mode_mouse mode)
691 {
692 	BPrivate::AppServerLink link;
693 	link.StartMessage(AS_SET_MOUSE_MODE);
694 	link.Attach<mode_mouse>(mode);
695 	link.Flush();
696 }
697 
698 
699 _IMPEXP_BE mode_mouse
700 mouse_mode()
701 {
702 	// Gets the focus-follows-mouse style, such as normal, B_WARP_MOUSE, etc.
703 	mode_mouse mode = B_NORMAL_MOUSE;
704 
705 	BPrivate::AppServerLink link;
706 	link.StartMessage(AS_GET_MOUSE_MODE);
707 
708 	int32 code;
709 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
710 		link.Read<mode_mouse>(&mode);
711 
712 	return mode;
713 }
714 
715 
716 _IMPEXP_BE rgb_color
717 ui_color(color_which which)
718 {
719 	int32 index = color_which_to_index(which);
720 	if (index < 0 || index >= kNumColors) {
721 		fprintf(stderr, "ui_color(): unknown color_which %d\n", which);
722 		return make_color(0, 0, 0);
723 	}
724 
725 	if (be_app) {
726 		server_read_only_memory* shared = BApplication::Private::ServerReadOnlyMemory();
727 		return shared->colors[index];
728 	}
729 
730 	return kDefaultColors[index];
731 }
732 
733 
734 _IMPEXP_BE void
735 set_ui_color(const color_which &which, const rgb_color &color)
736 {
737 	int32 index = color_which_to_index(which);
738 	if (index < 0 || index >= kNumColors) {
739 		fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which);
740 		return;
741 	}
742 
743 	BPrivate::AppServerLink link;
744 	link.StartMessage(AS_SET_UI_COLOR);
745 	link.Attach<color_which>(which);
746 	link.Attach<rgb_color>(color);
747 	link.Flush();
748 }
749 
750 
751 _IMPEXP_BE rgb_color
752 tint_color(rgb_color color, float tint)
753 {
754 	rgb_color result;
755 
756 	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
757 	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
758 
759 	if (tint < 1.0f) {
760 		result.red   = LIGHTEN(color.red);
761 		result.green = LIGHTEN(color.green);
762 		result.blue  = LIGHTEN(color.blue);
763 		result.alpha = color.alpha;
764 	} else {
765 		result.red   = DARKEN(color.red);
766 		result.green = DARKEN(color.green);
767 		result.blue  = DARKEN(color.blue);
768 		result.alpha = color.alpha;
769 	}
770 
771 	#undef LIGHTEN
772 	#undef DARKEN
773 
774 	return result;
775 }
776 
777 
778 rgb_color shift_color(rgb_color color, float shift);
779 
780 rgb_color
781 shift_color(rgb_color color, float shift)
782 {
783 	return tint_color(color, shift);
784 }
785 
786 
787 extern "C" status_t
788 _init_interface_kit_()
789 {
790 	sem_id widthSem = create_sem(0, "BTextView WidthBuffer Sem");
791 	if (widthSem < 0)
792 		return widthSem;
793 	BTextView::sWidthSem = widthSem;
794 	BTextView::sWidthAtom = 0;
795 	BTextView::sWidths = new _BWidthBuffer_;
796 
797 	_init_global_fonts_();
798 
799 	_menu_info_ptr_ = &BMenu::sMenuInfo;
800 	status_t status = get_menu_info(&BMenu::sMenuInfo);
801 
802 	general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR);
803 	general_info.mark_color.set_to(0, 0, 0);
804 	general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
805 	general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR);
806 	general_info.color_frame = true;
807 
808 	// TODO: fill the other static members
809 
810 	return status;
811 }
812 
813 
814 extern "C" status_t
815 _fini_interface_kit_()
816 {
817 	//TODO: Implement ?
818 
819 	return B_OK;
820 }
821 
822 
823 //	#pragma mark -
824 
825 
826 /*!
827 	\brief private function used by Deskbar to set window decor
828 	Note, we don't have to be compatible here, and could just change
829 	the Deskbar not to use this anymore
830 	\param theme The theme to choose
831 
832 	- \c 0: BeOS
833 	- \c 1: AmigaOS
834 	- \c 2: Win95
835 	- \c 3: MacOS
836 */
837 void
838 __set_window_decor(int32 theme)
839 {
840 	BPrivate::AppServerLink link;
841 	link.StartMessage(AS_R5_SET_DECORATOR);
842 	link.Attach<int32>(theme);
843 	link.Flush();
844 }
845 
846 
847 namespace BPrivate {
848 
849 /*!
850 	\brief queries the server for the number of available decorators
851 	\return the number of available decorators
852 */
853 int32
854 count_decorators(void)
855 {
856 	BPrivate::AppServerLink link;
857 	link.StartMessage(AS_COUNT_DECORATORS);
858 
859 	int32 code;
860 	int32 count = -1;
861 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
862 		link.Read<int32>(&count);
863 
864 	return count;
865 }
866 
867 /*!
868 	\brief queries the server for the index of the current decorators
869 	\return the current decorator's index
870 
871 	If for some bizarre reason this function fails, it returns -1
872 */
873 int32
874 get_decorator(void)
875 {
876 	BPrivate::AppServerLink link;
877 	link.StartMessage(AS_GET_DECORATOR);
878 
879 	int32 code;
880 	int32 index = -1;
881 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
882 		link.Read<int32>(&index);
883 
884 	return index;
885 }
886 
887 
888 /*!
889 	\brief queries the server for the name of the decorator with a certain index
890 	\param index The index of the decorator to get the name for
891 	\param name BString to receive the name of the decorator
892 	\return B_OK if successful, B_ERROR if not
893 */
894 status_t
895 get_decorator_name(const int32 &index, BString &name)
896 {
897 	BPrivate::AppServerLink link;
898 	link.StartMessage(AS_GET_DECORATOR_NAME);
899 	link.Attach<int32>(index);
900 
901 	int32 code;
902 	if (link.FlushWithReply(code) == B_OK && code == B_OK) {
903 		char *string;
904 		if (link.ReadString(&string) == B_OK) {
905 			name = string;
906 			free(string);
907 			return B_OK;
908 		}
909 	}
910 
911 	return B_ERROR;
912 }
913 
914 /*!
915 	\brief asks the server to draw a decorator preview into a BBitmap
916 	\param index The index of the decorator to get the name for
917 	\param bitmap BBitmap to receive the preview
918 	\return B_OK if successful, B_ERROR if not.
919 
920 	This is currently unimplemented.
921 */
922 status_t
923 get_decorator_preview(const int32 &index, BBitmap *bitmap)
924 {
925 	// TODO: implement get_decorator_preview
926 	return B_ERROR;
927 }
928 
929 
930 /*!
931 	\brief Private function which sets the window decorator for the system.
932 	\param index Index of the decorator to set
933 
934 	If the index is invalid, this function and the server do nothing
935 */
936 status_t
937 set_decorator(const int32 &index)
938 {
939 	if (index < 0)
940 		return B_BAD_VALUE;
941 
942 	BPrivate::AppServerLink link;
943 
944 	link.StartMessage(AS_SET_DECORATOR);
945 	link.Attach<int32>(index);
946 	link.Flush();
947 
948 	return B_OK;
949 }
950 
951 }	// namespace BPrivate
952 
953 // These methods were marked with "Danger, will Robinson!" in
954 // the OpenTracker source, so we might not want to be compatible
955 // here.
956 // In any way, we would need to update Deskbar to use our
957 // replacements, so we could as well just implement them...
958 //
959 // They are defined (also the complete window_info structure) in
960 // src/apps/deskbar/WindowMenuItem.h
961 
962 struct window_info;
963 
964 void do_window_action(int32 window_id, int32 action,
965 		BRect zoomRect, bool zoom);
966 window_info	*get_window_info(int32 a_token);
967 int32 *get_token_list(team_id app, int32 *count);
968 void do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom);
969 void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
970 
971 
972 void
973 do_window_action(int32 windowToken, int32 action,
974 	BRect zoomRect, bool zoom)
975 {
976 	BPrivate::AppServerLink link;
977 
978 	link.StartMessage(AS_WINDOW_ACTION);
979 	link.Attach<int32>(windowToken);
980 	link.Attach<int32>(action);
981 		// we don't have any zooming effect
982 
983 	link.Flush();
984 }
985 
986 
987 window_info	*
988 get_window_info(int32 serverToken)
989 {
990 	BPrivate::AppServerLink link;
991 
992 	link.StartMessage(AS_GET_WINDOW_INFO);
993 	link.Attach<int32>(serverToken);
994 
995 	int32 code;
996 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
997 		return NULL;
998 
999 	int32 size;
1000 	link.Read<int32>(&size);
1001 
1002 	client_window_info* info = (client_window_info*)malloc(size);
1003 	if (info == NULL)
1004 		return NULL;
1005 
1006 	link.Read(info, size);
1007 	return info;
1008 }
1009 
1010 
1011 int32 *
1012 get_token_list(team_id team, int32 *_count)
1013 {
1014 	BPrivate::AppServerLink link;
1015 
1016 	link.StartMessage(AS_GET_WINDOW_LIST);
1017 	link.Attach<team_id>(team);
1018 
1019 	int32 code;
1020 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1021 		return NULL;
1022 
1023 	int32 count;
1024 	link.Read<int32>(&count);
1025 
1026 	int32* tokens = (int32*)malloc(count * sizeof(int32));
1027 	if (tokens == NULL)
1028 		return NULL;
1029 
1030 	link.Read(tokens, count * sizeof(int32));
1031 	*_count = count;
1032 	return tokens;
1033 }
1034 
1035 
1036 void
1037 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom)
1038 {
1039 	BPrivate::AppServerLink link;
1040 
1041 	link.StartMessage(AS_BRING_TEAM_TO_FRONT);
1042 	link.Attach<team_id>(team);
1043 		// we don't have any zooming effect
1044 
1045 	link.Flush();
1046 }
1047 
1048 
1049 void
1050 do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1051 {
1052 	BPrivate::AppServerLink link;
1053 
1054 	link.StartMessage(AS_MINIMIZE_TEAM);
1055 	link.Attach<team_id>(team);
1056 		// we don't have any zooming effect
1057 
1058 	link.Flush();
1059 }
1060 
1061 
1062 //	#pragma mark - truncate string
1063 
1064 
1065 static char*
1066 write_ellipsis(char* dst)
1067 {
1068 	strcpy(dst, B_UTF8_ELLIPSIS);
1069 	// The UTF-8 character spans over 3 bytes
1070 	return dst + 3;
1071 }
1072 
1073 
1074 bool
1075 truncate_end(const char* source, char* dest, uint32 numChars,
1076 	const float* escapementArray, float width, float ellipsisWidth, float size)
1077 {
1078 	float currentWidth = 0.0;
1079 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1080 	width /= size;
1081 	uint32 lastFit = 0, c;
1082 
1083 	for (c = 0; c < numChars; c++) {
1084 		currentWidth += escapementArray[c];
1085 		if (currentWidth + ellipsisWidth <= width)
1086 			lastFit = c;
1087 
1088 		if (currentWidth > width)
1089 			break;
1090 	}
1091 
1092 	if (c == numChars) {
1093 		// string fits into width
1094 		return false;
1095 	}
1096 
1097 	if (c == 0) {
1098 		// there is no space for the ellipsis
1099 		strcpy(dest, "");
1100 		return true;
1101 	}
1102 
1103 	// copy string to destination
1104 
1105 	for (uint32 i = 0; i < lastFit + 1; i++) {
1106 		// copy one glyph
1107 		do {
1108 			*dest++ = *source++;
1109 		} while (IsInsideGlyph(*source));
1110 	}
1111 
1112 	// write ellipsis and terminate
1113 
1114 	dest = write_ellipsis(dest);
1115 	*dest = '\0';
1116 	return true;
1117 }
1118 
1119 
1120 static char*
1121 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length,
1122 	const float* escapementArray, float width, float ellipsisWidth, float size)
1123 {
1124 	const char* originalStart = src;
1125 	src += length - 1;
1126 	float currentWidth = 0.0;
1127 	for (int32 c = numChars - 1; c > 0; c--) {
1128 		currentWidth += escapementArray[c] * size;
1129 		if (currentWidth > width) {
1130 			// ups, we definitely don't fit. go back until the ellipsis fits
1131 			currentWidth += ellipsisWidth;
1132 			// go forward again until ellipsis fits (already beyond the target)
1133 			for (uint32 c2 = c; c2 < numChars; c2++) {
1134 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size);
1135 				currentWidth -= escapementArray[c2] * size;
1136 				do {
1137 					src++;
1138 				} while (IsInsideGlyph(*src));
1139 				// see if we went back enough
1140 				if (currentWidth <= width)
1141 					break;
1142 			}
1143 			break;
1144 		} else {
1145 			// go back one glyph
1146 			do {
1147 				src--;
1148 			} while (IsInsideGlyph(*src));
1149 		}
1150 	}
1151 	// copy from the end of the string
1152 	uint32 bytesToCopy = originalStart + length - src;
1153 	memcpy(dst, src, bytesToCopy);
1154 	dst += bytesToCopy;
1155 	return dst;
1156 }
1157 
1158 
1159 bool
1160 truncate_middle(const char* source, char* dest, uint32 numChars,
1161 	const float* escapementArray, float width, float ellipsisWidth, float size)
1162 {
1163 	// find visual center
1164 
1165 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1166 	width /= size;
1167 
1168 	float halfWidth = (width - ellipsisWidth) / 2.0;
1169 	float leftWidth = 0.0, rightWidth = 0.0;
1170 	uint32 left, right;
1171 
1172 	// coming from left...
1173 
1174 	for (left = 0; left < numChars; left++) {
1175 		if (leftWidth + escapementArray[left] > halfWidth)
1176 			break;
1177 
1178 		leftWidth += escapementArray[left];
1179 	}
1180 
1181 	if (left == numChars) {
1182 		// string is smaller than half of the maximum width
1183 		return false;
1184 	}
1185 
1186 	// coming from right...
1187 
1188 	for (right = numChars; right-- > left; ) {
1189 		if (rightWidth + escapementArray[right] > halfWidth)
1190 			break;
1191 
1192 		rightWidth += escapementArray[right];
1193 	}
1194 
1195 	if (left >= right) {
1196 		// string is smaller than the maximum width
1197 		return false;
1198 	}
1199 
1200 	if (left == 0 || right >= numChars - 1) {
1201 		// there is no space for the ellipsis
1202 		strcpy(dest, "");
1203 		return true;
1204 	}
1205 
1206 	// see if the gap between left/right is smaller than the ellipsis
1207 
1208 	float totalWidth = rightWidth + leftWidth;
1209 
1210 	for (uint32 i = left; i < right; i++) {
1211 		totalWidth += escapementArray[i];
1212 		if (totalWidth > width)
1213 			break;
1214 	}
1215 
1216 	if (totalWidth <= width) {
1217 		// the whole string fits!
1218 		return false;
1219 	}
1220 
1221 	// The ellipsis now definitely fits, but let's
1222 	// see if we can add another character
1223 
1224 	totalWidth = ellipsisWidth + rightWidth + leftWidth;
1225 
1226 	if (left > numChars - right) {
1227 		// try right letter first
1228 		if (escapementArray[right] + totalWidth <= width)
1229 			right--;
1230 		else if (escapementArray[left] + totalWidth <= width)
1231 			left++;
1232 	} else {
1233 		// try left letter first
1234 		if (escapementArray[left] + totalWidth <= width)
1235 			left++;
1236 		else if (escapementArray[right] + totalWidth <= width)
1237 			right--;
1238 	}
1239 
1240 	// copy characters
1241 
1242 	for (uint32 i = 0; i < left; i++) {
1243 		// copy one glyph
1244 		do {
1245 			*dest++ = *source++;
1246 		} while (IsInsideGlyph(*source));
1247 	}
1248 
1249 	dest = write_ellipsis(dest);
1250 
1251 	for (uint32 i = left; i < numChars; i++) {
1252 		// copy one glyph
1253 		do {
1254 			if (i >= right)
1255 				*dest++ = *source++;
1256 			else
1257 				source++;
1258 		} while (IsInsideGlyph(*source));
1259 	}
1260 
1261 	// terminate
1262 	dest[0] = '\0';
1263 	return true;
1264 }
1265 
1266 
1267 // ToDo: put into BPrivate namespace
1268 void
1269 truncate_string(const char* string, uint32 mode, float width,
1270 	char* result, const float* escapementArray, float fontSize,
1271 	float ellipsisWidth, int32 length, int32 numChars)
1272 {
1273 	// ToDo: that's actually not correct: the string could be smaller than ellipsisWidth
1274 	if (string == NULL /*|| width < ellipsisWidth*/) {
1275 		// we don't have room for a single glyph
1276 		strcpy(result, "");
1277 		return;
1278 	}
1279 
1280 	// iterate over glyphs and copy source into result string
1281 	// one glyph at a time as long as we have room for the "…" yet
1282 	char* dest = result;
1283 	const char* source = string;
1284 	bool truncated = true;
1285 
1286 	switch (mode) {
1287 		case B_TRUNCATE_BEGINNING: {
1288 			dest = copy_from_end(source, dest, numChars, length,
1289 				escapementArray, width, ellipsisWidth, fontSize);
1290 			// "dst" points to the position behind the last glyph that
1291 			// was copied.
1292 			int32 dist = dest - result;
1293 			// we didn't terminate yet
1294 			*dest = 0;
1295 			if (dist < length) {
1296 				// TODO: Is there a smarter way?
1297 				char* temp = new char[dist + 4];
1298 				char* t = temp;
1299 				// append "…"
1300 				t = write_ellipsis(t);
1301 				// shuffle arround strings so that "…" is prepended
1302 				strcpy(t, result);
1303 				strcpy(result, temp);
1304 				delete[] temp;
1305 /*						char t = result[3];
1306 				memmove(&result[3], result, dist + 1);
1307 				write_ellipsis(result);
1308 				result[3] = t;*/
1309 			}
1310 			break;
1311 		}
1312 
1313 		case B_TRUNCATE_END:
1314 			truncated = truncate_end(source, dest, numChars, escapementArray,
1315 				width, ellipsisWidth, fontSize);
1316 			break;
1317 
1318 		case B_TRUNCATE_SMART:
1319 			// TODO: implement, though it was never implemented on R5
1320 			// FALL THROUGH (at least do something)
1321 		case B_TRUNCATE_MIDDLE:
1322 			truncated = truncate_middle(source, dest, numChars, escapementArray,
1323 				width, ellipsisWidth, fontSize);
1324 			break;
1325 	}
1326 
1327 	if (!truncated) {
1328 		// copy string to destination verbatim
1329 		strlcpy(dest, source, length + 1);
1330 	}
1331 }
1332 
1333