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