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