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