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