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