xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision 0975f16f7ca94b654cb6a55b3316daae89843abb)
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[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) {
1080 		server_read_only_memory* shared
1081 			= BApplication::Private::ServerReadOnlyMemory();
1082 		return shared->colors[index];
1083 	}
1084 
1085 	return kDefaultColors[index];
1086 }
1087 
1088 
1089 void
1090 set_ui_color(const color_which &which, const rgb_color &color)
1091 {
1092 	int32 index = color_which_to_index(which);
1093 	if (index < 0 || index >= kColorWhichCount) {
1094 		fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which);
1095 		return;
1096 	}
1097 
1098 	BPrivate::AppServerLink link;
1099 	link.StartMessage(AS_SET_UI_COLOR);
1100 	link.Attach<color_which>(which);
1101 	link.Attach<rgb_color>(color);
1102 	link.Flush();
1103 }
1104 
1105 
1106 rgb_color
1107 tint_color(rgb_color color, float tint)
1108 {
1109 	rgb_color result;
1110 
1111 	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
1112 	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
1113 
1114 	if (tint < 1.0f) {
1115 		result.red   = LIGHTEN(color.red);
1116 		result.green = LIGHTEN(color.green);
1117 		result.blue  = LIGHTEN(color.blue);
1118 		result.alpha = color.alpha;
1119 	} else {
1120 		result.red   = DARKEN(color.red);
1121 		result.green = DARKEN(color.green);
1122 		result.blue  = DARKEN(color.blue);
1123 		result.alpha = color.alpha;
1124 	}
1125 
1126 	#undef LIGHTEN
1127 	#undef DARKEN
1128 
1129 	return result;
1130 }
1131 
1132 
1133 rgb_color shift_color(rgb_color color, float shift);
1134 
1135 rgb_color
1136 shift_color(rgb_color color, float shift)
1137 {
1138 	return tint_color(color, shift);
1139 }
1140 
1141 
1142 extern "C" status_t
1143 _init_interface_kit_()
1144 {
1145 	status_t status = BPrivate::PaletteConverter::InitializeDefault(true);
1146 	if (status < B_OK)
1147 		return status;
1148 
1149 	// init global clipboard
1150 	if (be_clipboard == NULL)
1151 		be_clipboard = new BClipboard(NULL);
1152 
1153 	// TODO: Could support different themes here in the future.
1154 	be_control_look = new BControlLook();
1155 
1156 	_init_global_fonts_();
1157 
1158 	BPrivate::gWidthBuffer = new BPrivate::WidthBuffer;
1159 	status = BPrivate::MenuPrivate::CreateBitmaps();
1160 	if (status != B_OK)
1161 		return status;
1162 
1163 	_menu_info_ptr_ = &BMenu::sMenuInfo;
1164 
1165 	status = get_menu_info(&BMenu::sMenuInfo);
1166 	if (status != B_OK)
1167 		return status;
1168 
1169 	general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR);
1170 	general_info.mark_color = ui_color(B_CONTROL_MARK_COLOR);
1171 	general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
1172 	general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR);
1173 	general_info.color_frame = true;
1174 
1175 	// TODO: fill the other static members
1176 
1177 	return status;
1178 }
1179 
1180 
1181 extern "C" status_t
1182 _fini_interface_kit_()
1183 {
1184 	BPrivate::MenuPrivate::DeleteBitmaps();
1185 
1186 	delete BPrivate::gWidthBuffer;
1187 	BPrivate::gWidthBuffer = NULL;
1188 
1189 	delete be_control_look;
1190 	be_control_look = NULL;
1191 
1192 	// TODO: Anything else?
1193 
1194 	return B_OK;
1195 }
1196 
1197 
1198 
1199 namespace BPrivate {
1200 
1201 
1202 /*!	\brief queries the server for the current decorator
1203 	\param ref entry_ref into which to store current decorator's location
1204 	\return boolean true/false
1205 */
1206 bool
1207 get_decorator(BString& path)
1208 {
1209 	BPrivate::AppServerLink link;
1210 	link.StartMessage(AS_GET_DECORATOR);
1211 
1212 	int32 code;
1213 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1214 		return false;
1215 
1216  	return link.ReadString(path) == B_OK;
1217 }
1218 
1219 
1220 /*!	\brief Private function which sets the window decorator for the system.
1221 	\param entry_ref to the decorator to set
1222 
1223 	Will return detailed error status via status_t
1224 */
1225 status_t
1226 set_decorator(const BString& path)
1227 {
1228 	BPrivate::AppServerLink link;
1229 
1230 	link.StartMessage(AS_SET_DECORATOR);
1231 
1232 	link.AttachString(path.String());
1233 	link.Flush();
1234 
1235 	status_t error = B_OK;
1236 	link.Read<status_t>(&error);
1237 
1238 	return error;
1239 }
1240 
1241 
1242 /*! \brief sets a window to preview a given decorator
1243 	\param path path to any given decorator add-on
1244 	\param window pointer to BWindow which will show decorator
1245 
1246 	Piggy-backs on BWindow::SetDecoratorSettings(...)
1247 */
1248 status_t
1249 preview_decorator(const BString& path, BWindow* window)
1250 {
1251 	if (window == NULL)
1252 		return B_ERROR;
1253 
1254 	BMessage msg('prVu');
1255 	msg.AddString("preview", path.String());
1256 
1257 	return window->SetDecoratorSettings(msg);
1258 }
1259 
1260 
1261 status_t
1262 get_application_order(int32 workspace, team_id** _applications,
1263 	int32* _count)
1264 {
1265 	BPrivate::AppServerLink link;
1266 
1267 	link.StartMessage(AS_GET_APPLICATION_ORDER);
1268 	link.Attach<int32>(workspace);
1269 
1270 	int32 code;
1271 	status_t status = link.FlushWithReply(code);
1272 	if (status != B_OK)
1273 		return status;
1274 	if (code != B_OK)
1275 		return code;
1276 
1277 	int32 count;
1278 	link.Read<int32>(&count);
1279 
1280 	*_applications = (team_id*)malloc(count * sizeof(team_id));
1281 	if (*_applications == NULL)
1282 		return B_NO_MEMORY;
1283 
1284 	link.Read(*_applications, count * sizeof(team_id));
1285 	*_count = count;
1286 	return B_OK;
1287 }
1288 
1289 
1290 status_t
1291 get_window_order(int32 workspace, int32** _tokens, int32* _count)
1292 {
1293 	BPrivate::AppServerLink link;
1294 
1295 	link.StartMessage(AS_GET_WINDOW_ORDER);
1296 	link.Attach<int32>(workspace);
1297 
1298 	int32 code;
1299 	status_t status = link.FlushWithReply(code);
1300 	if (status != B_OK)
1301 		return status;
1302 	if (code != B_OK)
1303 		return code;
1304 
1305 	int32 count;
1306 	link.Read<int32>(&count);
1307 
1308 	*_tokens = (int32*)malloc(count * sizeof(int32));
1309 	if (*_tokens == NULL)
1310 		return B_NO_MEMORY;
1311 
1312 	link.Read(*_tokens, count * sizeof(int32));
1313 	*_count = count;
1314 	return B_OK;
1315 }
1316 
1317 
1318 }	// namespace BPrivate
1319 
1320 // These methods were marked with "Danger, will Robinson!" in
1321 // the OpenTracker source, so we might not want to be compatible
1322 // here.
1323 // In any way, we would need to update Deskbar to use our
1324 // replacements, so we could as well just implement them...
1325 
1326 void
1327 do_window_action(int32 windowToken, int32 action, BRect zoomRect, bool zoom)
1328 {
1329 	BPrivate::AppServerLink link;
1330 
1331 	link.StartMessage(AS_WINDOW_ACTION);
1332 	link.Attach<int32>(windowToken);
1333 	link.Attach<int32>(action);
1334 		// we don't have any zooming effect
1335 
1336 	link.Flush();
1337 }
1338 
1339 
1340 client_window_info*
1341 get_window_info(int32 serverToken)
1342 {
1343 	BPrivate::AppServerLink link;
1344 
1345 	link.StartMessage(AS_GET_WINDOW_INFO);
1346 	link.Attach<int32>(serverToken);
1347 
1348 	int32 code;
1349 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1350 		return NULL;
1351 
1352 	int32 size;
1353 	link.Read<int32>(&size);
1354 
1355 	client_window_info* info = (client_window_info*)malloc(size);
1356 	if (info == NULL)
1357 		return NULL;
1358 
1359 	link.Read(info, size);
1360 	return info;
1361 }
1362 
1363 
1364 int32*
1365 get_token_list(team_id team, int32* _count)
1366 {
1367 	BPrivate::AppServerLink link;
1368 
1369 	link.StartMessage(AS_GET_WINDOW_LIST);
1370 	link.Attach<team_id>(team);
1371 
1372 	int32 code;
1373 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1374 		return NULL;
1375 
1376 	int32 count;
1377 	link.Read<int32>(&count);
1378 
1379 	int32* tokens = (int32*)malloc(count * sizeof(int32));
1380 	if (tokens == NULL)
1381 		return NULL;
1382 
1383 	link.Read(tokens, count * sizeof(int32));
1384 	*_count = count;
1385 	return tokens;
1386 }
1387 
1388 
1389 void
1390 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom)
1391 {
1392 	BPrivate::AppServerLink link;
1393 
1394 	link.StartMessage(AS_BRING_TEAM_TO_FRONT);
1395 	link.Attach<team_id>(team);
1396 		// we don't have any zooming effect
1397 
1398 	link.Flush();
1399 }
1400 
1401 
1402 void
1403 do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1404 {
1405 	BPrivate::AppServerLink link;
1406 
1407 	link.StartMessage(AS_MINIMIZE_TEAM);
1408 	link.Attach<team_id>(team);
1409 		// we don't have any zooming effect
1410 
1411 	link.Flush();
1412 }
1413 
1414 
1415 //	#pragma mark - truncate string
1416 
1417 
1418 void
1419 truncate_string(BString& string, uint32 mode, float width,
1420 	const float* escapementArray, float fontSize, float ellipsisWidth,
1421 	int32 charCount)
1422 {
1423 	// add a tiny amount to the width to make floating point inaccuracy
1424 	// not drop chars that would actually fit exactly
1425 	width += 1.f / 128;
1426 
1427 	switch (mode) {
1428 		case B_TRUNCATE_BEGINNING:
1429 		{
1430 			float totalWidth = 0;
1431 			for (int32 i = charCount - 1; i >= 0; i--) {
1432 				float charWidth = escapementArray[i] * fontSize;
1433 				if (totalWidth + charWidth > width) {
1434 					// we need to truncate
1435 					while (totalWidth + ellipsisWidth > width) {
1436 						// remove chars until there's enough space for the
1437 						// ellipsis
1438 						if (++i == charCount) {
1439 							// we've reached the end of the string and still
1440 							// no space, so return an empty string
1441 							string.Truncate(0);
1442 							return;
1443 						}
1444 
1445 						totalWidth -= escapementArray[i] * fontSize;
1446 					}
1447 
1448 					string.RemoveChars(0, i + 1);
1449 					string.PrependChars(B_UTF8_ELLIPSIS, 1);
1450 					return;
1451 				}
1452 
1453 				totalWidth += charWidth;
1454 			}
1455 
1456 			break;
1457 		}
1458 
1459 		case B_TRUNCATE_END:
1460 		{
1461 			float totalWidth = 0;
1462 			for (int32 i = 0; i < charCount; i++) {
1463 				float charWidth = escapementArray[i] * fontSize;
1464 				if (totalWidth + charWidth > width) {
1465 					// we need to truncate
1466 					while (totalWidth + ellipsisWidth > width) {
1467 						// remove chars until there's enough space for the
1468 						// ellipsis
1469 						if (i-- == 0) {
1470 							// we've reached the start of the string and still
1471 							// no space, so return an empty string
1472 							string.Truncate(0);
1473 							return;
1474 						}
1475 
1476 						totalWidth -= escapementArray[i] * fontSize;
1477 					}
1478 
1479 					string.RemoveChars(i, charCount - i);
1480 					string.AppendChars(B_UTF8_ELLIPSIS, 1);
1481 					return;
1482 				}
1483 
1484 				totalWidth += charWidth;
1485 			}
1486 
1487 			break;
1488 		}
1489 
1490 		case B_TRUNCATE_MIDDLE:
1491 		case B_TRUNCATE_SMART:
1492 		{
1493 			float leftWidth = 0;
1494 			float rightWidth = 0;
1495 			int32 leftIndex = 0;
1496 			int32 rightIndex = charCount - 1;
1497 			bool left = true;
1498 
1499 			for (int32 i = 0; i < charCount; i++) {
1500 				float charWidth
1501 					= escapementArray[left ? leftIndex : rightIndex] * fontSize;
1502 
1503 				if (leftWidth + rightWidth + charWidth > width) {
1504 					// we need to truncate
1505 					while (leftWidth + rightWidth + ellipsisWidth > width) {
1506 						// remove chars until there's enough space for the
1507 						// ellipsis
1508 						if (leftIndex == 0 && rightIndex == charCount - 1) {
1509 							// we've reached both ends of the string and still
1510 							// no space, so return an empty string
1511 							string.Truncate(0);
1512 							return;
1513 						}
1514 
1515 						if (leftIndex > 0 && (rightIndex == charCount - 1
1516 								|| leftWidth > rightWidth)) {
1517 							// remove char on the left
1518 							leftWidth -= escapementArray[--leftIndex]
1519 								* fontSize;
1520 						} else {
1521 							// remove char on the right
1522 							rightWidth -= escapementArray[++rightIndex]
1523 								* fontSize;
1524 						}
1525 					}
1526 
1527 					string.RemoveChars(leftIndex, rightIndex + 1 - leftIndex);
1528 					string.InsertChars(B_UTF8_ELLIPSIS, 1, leftIndex);
1529 					return;
1530 				}
1531 
1532 				if (left) {
1533 					leftIndex++;
1534 					leftWidth += charWidth;
1535 				} else {
1536 					rightIndex--;
1537 					rightWidth += charWidth;
1538 				}
1539 
1540 				left = rightWidth > leftWidth;
1541 			}
1542 
1543 			break;
1544 		}
1545 	}
1546 
1547 	// we've run through without the need to truncate, leave the string as it is
1548 }
1549