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