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