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