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