xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
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 static bool
1237 optional_char_fits(float escapement, float fontSize, float gap)
1238 {
1239 	const float size = escapement * fontSize;
1240 	if (size <= gap || fabs(size - gap) <= 0.0001)
1241 		return true;
1242 	return false;
1243 }
1244 
1245 
1246 bool
1247 truncate_end(const char* source, char* dest, uint32 numChars,
1248 	const float* escapementArray, float width, float ellipsisWidth, float size)
1249 {
1250 	float currentWidth = 0.0;
1251 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1252 	width /= size;
1253 	uint32 lastFit = 0, c;
1254 
1255 	for (c = 0; c < numChars; c++) {
1256 		currentWidth += escapementArray[c];
1257 		if (currentWidth + ellipsisWidth <= width)
1258 			lastFit = c;
1259 
1260 		if (currentWidth > width)
1261 			break;
1262 	}
1263 
1264 	if (c == numChars) {
1265 		// string fits into width
1266 		return false;
1267 	}
1268 
1269 	if (c == 0) {
1270 		// there is no space for the ellipsis
1271 		strcpy(dest, "");
1272 		return true;
1273 	}
1274 
1275 	// copy string to destination
1276 
1277 	for (uint32 i = 0; i < lastFit + 1; i++) {
1278 		// copy one glyph
1279 		do {
1280 			*dest++ = *source++;
1281 		} while (IsInsideGlyph(*source));
1282 	}
1283 
1284 	// write ellipsis and terminate
1285 
1286 	dest = write_ellipsis(dest);
1287 	*dest = '\0';
1288 	return true;
1289 }
1290 
1291 
1292 static char*
1293 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length,
1294 	const float* escapementArray, float width, float ellipsisWidth, float size)
1295 {
1296 	const char* originalStart = src;
1297 	src += length - 1;
1298 	float currentWidth = 0.0;
1299 	for (int32 c = numChars - 1; c > 0; c--) {
1300 		currentWidth += escapementArray[c] * size;
1301 		if (currentWidth > width) {
1302 			// ups, we definitely don't fit. go back until the ellipsis fits
1303 			currentWidth += ellipsisWidth;
1304 			// go forward again until ellipsis fits (already beyond the target)
1305 			for (uint32 c2 = c; c2 < numChars; c2++) {
1306 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size);
1307 				currentWidth -= escapementArray[c2] * size;
1308 				do {
1309 					src++;
1310 				} while (IsInsideGlyph(*src));
1311 				// see if we went back enough
1312 				if (currentWidth <= width)
1313 					break;
1314 			}
1315 			break;
1316 		} else {
1317 			// go back one glyph
1318 			do {
1319 				src--;
1320 			} while (IsInsideGlyph(*src));
1321 		}
1322 	}
1323 	// copy from the end of the string
1324 	uint32 bytesToCopy = originalStart + length - src;
1325 	memcpy(dst, src, bytesToCopy);
1326 	dst += bytesToCopy;
1327 	return dst;
1328 }
1329 
1330 
1331 bool
1332 truncate_middle(const char* source, char* dest, uint32 numChars,
1333 	const float* escapementArray, float width, float ellipsisWidth, float size)
1334 {
1335 	float mid = (width - ellipsisWidth) / 2.0;
1336 
1337 	uint32 left = 0;
1338 	float leftWidth = 0.0;
1339 	while (left < numChars && (leftWidth + (escapementArray[left] * size)) < mid)
1340 		leftWidth += (escapementArray[left++] * size);
1341 
1342 	if (left == numChars)
1343 		return false;
1344 
1345 	float rightWidth = 0.0;
1346 	uint32 right = numChars;
1347 	while (right > left && (rightWidth + (escapementArray[right - 1] * size)) < mid)
1348 		rightWidth += (escapementArray[--right] * size);
1349 
1350 	if (left >= right)
1351 		return false;
1352 
1353 	float stringWidth = leftWidth + rightWidth;
1354 	for (uint32 i = left; i < right; ++i)
1355 		stringWidth += (escapementArray[i] * size);
1356 
1357 	if (stringWidth <= width)
1358 		return false;
1359 
1360 	// if there is no space for the ellipsis
1361 	if (width < ellipsisWidth) {
1362 		strcpy(dest, "");
1363 		return true;
1364 	}
1365 
1366 	// The ellipsis now definitely fits, but let's
1367 	// see if we can add another character
1368 	float gap = width - (leftWidth + ellipsisWidth + rightWidth);
1369 	if (left > numChars - right) {
1370 		// try right letter first
1371 		if (optional_char_fits(escapementArray[right - 1], size, gap)) {
1372 			right--;
1373 		} else if (optional_char_fits(escapementArray[left], size, gap)) {
1374 			left++;
1375 		}
1376 	} else {
1377 		// try left letter first
1378 		if (optional_char_fits(escapementArray[left], size, gap)) {
1379 			left++;
1380 		} else if (optional_char_fits(escapementArray[right - 1], size, gap)) {
1381 			right--;
1382 		}
1383 	}
1384 
1385 	// copy characters
1386 
1387 	for (uint32 i = 0; i < left; i++) {
1388 		// copy one glyph
1389 		do {
1390 			*dest++ = *source++;
1391 		} while (IsInsideGlyph(*source));
1392 	}
1393 
1394 	dest = write_ellipsis(dest);
1395 
1396 	for (uint32 i = left; i < numChars; i++) {
1397 		// copy one glyph
1398 		do {
1399 			if (i >= right)
1400 				*dest++ = *source++;
1401 			else
1402 				source++;
1403 		} while (IsInsideGlyph(*source));
1404 	}
1405 
1406 	// terminate
1407 	dest[0] = '\0';
1408 	return true;
1409 }
1410 
1411 
1412 // TODO: put into BPrivate namespace
1413 void
1414 truncate_string(const char* string, uint32 mode, float width,
1415 	char* result, const float* escapementArray, float fontSize,
1416 	float ellipsisWidth, int32 length, int32 numChars)
1417 {
1418 	// TODO: that's actually not correct: the string could be smaller than ellipsisWidth
1419 	if (string == NULL /*|| width < ellipsisWidth*/) {
1420 		// we don't have room for a single glyph
1421 		strcpy(result, "");
1422 		return;
1423 	}
1424 
1425 	// iterate over glyphs and copy source into result string
1426 	// one glyph at a time as long as we have room for the "…" yet
1427 	char* dest = result;
1428 	const char* source = string;
1429 	bool truncated = true;
1430 
1431 	switch (mode) {
1432 		case B_TRUNCATE_BEGINNING: {
1433 			dest = copy_from_end(source, dest, numChars, length,
1434 				escapementArray, width, ellipsisWidth, fontSize);
1435 			// "dst" points to the position behind the last glyph that
1436 			// was copied.
1437 			int32 dist = dest - result;
1438 			// we didn't terminate yet
1439 			*dest = 0;
1440 			if (dist < length) {
1441 				// TODO: Is there a smarter way?
1442 				char* temp = new char[dist + 4];
1443 				char* t = temp;
1444 				// append "…"
1445 				t = write_ellipsis(t);
1446 				// shuffle arround strings so that "…" is prepended
1447 				strcpy(t, result);
1448 				strcpy(result, temp);
1449 				delete[] temp;
1450 /*						char t = result[3];
1451 				memmove(&result[3], result, dist + 1);
1452 				write_ellipsis(result);
1453 				result[3] = t;*/
1454 			}
1455 			break;
1456 		}
1457 
1458 		case B_TRUNCATE_END:
1459 			truncated = truncate_end(source, dest, numChars, escapementArray,
1460 				width, ellipsisWidth, fontSize);
1461 			break;
1462 
1463 		case B_TRUNCATE_SMART:
1464 			// TODO: implement, though it was never implemented on R5
1465 			// FALL THROUGH (at least do something)
1466 		case B_TRUNCATE_MIDDLE:
1467 		default:
1468 			truncated = truncate_middle(source, dest, numChars, escapementArray,
1469 				width, ellipsisWidth, fontSize);
1470 			break;
1471 	}
1472 
1473 	if (!truncated) {
1474 		// copy string to destination verbatim
1475 		strlcpy(dest, source, length + 1);
1476 	}
1477 }
1478 
1479