4 * Copyright 2013-2017 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 package org
.winehq
.wine
;
23 import android
.annotation
.TargetApi
;
24 import android
.app
.Activity
;
25 import android
.app
.ProgressDialog
;
26 import android
.content
.Context
;
27 import android
.content
.SharedPreferences
;
28 import android
.graphics
.Bitmap
;
29 import android
.graphics
.Rect
;
30 import android
.graphics
.SurfaceTexture
;
31 import android
.os
.Build
;
32 import android
.os
.Bundle
;
33 import android
.preference
.PreferenceManager
;
34 import android
.util
.Log
;
35 import android
.view
.InputDevice
;
36 import android
.view
.KeyEvent
;
37 import android
.view
.MotionEvent
;
38 import android
.view
.PointerIcon
;
39 import android
.view
.Surface
;
40 import android
.view
.TextureView
;
41 import android
.view
.View
;
42 import android
.view
.ViewGroup
;
43 import java
.io
.BufferedReader
;
45 import java
.io
.FileInputStream
;
46 import java
.io
.FileOutputStream
;
47 import java
.io
.IOException
;
48 import java
.io
.InputStream
;
49 import java
.io
.InputStreamReader
;
50 import java
.util
.ArrayList
;
51 import java
.util
.HashMap
;
52 import java
.util
.Locale
;
55 public class WineActivity
extends Activity
57 private native String
wine_init( String
[] cmdline
, String
[] env
);
58 public native void wine_desktop_changed( int width
, int height
);
59 public native void wine_config_changed( int dpi
);
60 public native void wine_surface_changed( int hwnd
, Surface surface
, boolean opengl
);
61 public native boolean wine_motion_event( int hwnd
, int action
, int x
, int y
, int state
, int vscroll
);
62 public native boolean wine_keyboard_event( int hwnd
, int action
, int keycode
, int state
);
64 private final String LOGTAG
= "wine";
65 private ProgressDialog progress_dialog
;
67 protected WineWindow desktop_window
;
68 protected WineWindow message_window
;
69 private PointerIcon current_cursor
;
72 public void onCreate(Bundle savedInstanceState
)
74 super.onCreate( savedInstanceState
);
76 requestWindowFeature( android
.view
.Window
.FEATURE_NO_TITLE
);
78 new Thread( new Runnable() { public void run() { loadWine( null ); }} ).start();
82 @SuppressWarnings("deprecation")
83 private String
[] get_supported_abis()
85 if (Build
.VERSION
.SDK_INT
>= 21) return Build
.SUPPORTED_ABIS
;
86 return new String
[]{ Build
.CPU_ABI
};
89 private String
get_wine_abi()
91 for (String abi
: get_supported_abis())
93 File server
= new File( getFilesDir(), abi
+ "/bin/wineserver" );
94 if (server
.canExecute()) return abi
;
96 Log
.e( LOGTAG
, "could not find a supported ABI" );
100 private void loadWine( String cmdline
)
104 String wine_abi
= get_wine_abi();
105 File bindir
= new File( getFilesDir(), wine_abi
+ "/bin" );
106 File libdir
= new File( getFilesDir(), wine_abi
+ "/lib" );
107 File dlldir
= new File( libdir
, "wine" );
108 File prefix
= new File( getFilesDir(), "prefix" );
109 File loader
= new File( bindir
, "wine" );
110 String locale
= Locale
.getDefault().getLanguage() + "_" +
111 Locale
.getDefault().getCountry() + ".UTF-8";
113 HashMap
<String
,String
> env
= new HashMap
<String
,String
>();
114 env
.put( "WINELOADER", loader
.toString() );
115 env
.put( "WINEPREFIX", prefix
.toString() );
116 env
.put( "WINEDLLPATH", dlldir
.toString() );
117 env
.put( "LD_LIBRARY_PATH", libdir
.toString() + ":" + getApplicationInfo().nativeLibraryDir
);
118 env
.put( "LC_ALL", locale
);
119 env
.put( "LANG", locale
);
120 env
.put( "PATH", bindir
.toString() + ":" + System
.getenv( "PATH" ));
124 if (new File( prefix
, "drive_c/winestart.cmd" ).exists()) cmdline
= "c:\\winestart.cmd";
125 else cmdline
= "wineconsole.exe";
128 String winedebug
= readFileString( new File( prefix
, "winedebug" ));
129 if (winedebug
== null) winedebug
= readFileString( new File( getFilesDir(), "winedebug" ));
130 if (winedebug
!= null)
132 File log
= new File( getFilesDir(), "log" );
133 env
.put( "WINEDEBUG", winedebug
);
134 env
.put( "WINEDEBUGLOG", log
.toString() );
135 Log
.i( LOGTAG
, "logging to " + log
.toString() );
139 createProgressDialog( 0, "Setting up the Windows environment..." );
141 System
.load( dlldir
.toString() + "/ntdll.so" );
144 runWine( cmdline
, env
);
147 private final void runWine( String cmdline
, HashMap
<String
,String
> environ
)
149 String
[] env
= new String
[environ
.size() * 2];
151 for (Map
.Entry
<String
,String
> entry
: environ
.entrySet())
153 env
[j
++] = entry
.getKey();
154 env
[j
++] = entry
.getValue();
157 String
[] cmd
= { environ
.get( "WINELOADER" ),
159 "/desktop=shell,,android",
162 String err
= wine_init( cmd
, env
);
163 Log
.e( LOGTAG
, err
);
166 private void createProgressDialog( final int max
, final String message
)
168 runOnUiThread( new Runnable() { public void run() {
169 if (progress_dialog
!= null) progress_dialog
.dismiss();
170 progress_dialog
= new ProgressDialog( WineActivity
.this );
171 progress_dialog
.setProgressStyle( max
> 0 ? ProgressDialog
.STYLE_HORIZONTAL
172 : ProgressDialog
.STYLE_SPINNER
);
173 progress_dialog
.setTitle( "Wine" );
174 progress_dialog
.setMessage( message
);
175 progress_dialog
.setCancelable( false );
176 progress_dialog
.setMax( max
);
177 progress_dialog
.show();
182 private final boolean isFileWanted( String name
)
184 if (name
.equals( "files.sum" )) return true;
185 if (name
.startsWith( "share/" )) return true;
186 for (String abi
: get_supported_abis())
188 if (name
.startsWith( abi
+ "/system/" )) return false;
189 if (name
.startsWith( abi
+ "/" )) return true;
191 if (name
.startsWith( "x86/" )) return true;
195 private final boolean isFileExecutable( String name
)
197 return !name
.equals( "files.sum" ) && !name
.startsWith( "share/" );
200 private final HashMap
<String
,String
> readMapFromInputStream( InputStream in
)
202 HashMap
<String
,String
> map
= new HashMap
<String
,String
>();
207 BufferedReader reader
= new BufferedReader( new InputStreamReader( in
, "UTF-8" ));
208 while ((str
= reader
.readLine()) != null)
210 String entry
[] = str
.split( "\\s+", 2 );
211 if (entry
.length
== 2 && isFileWanted( entry
[1] )) map
.put( entry
[1], entry
[0] );
214 catch( IOException e
) { }
218 private final HashMap
<String
,String
> readMapFromDiskFile( String file
)
222 return readMapFromInputStream( new FileInputStream( new File( getFilesDir(), file
)));
224 catch( IOException e
) { return new HashMap
<String
,String
>(); }
227 private final HashMap
<String
,String
> readMapFromAssetFile( String file
)
231 return readMapFromInputStream( getAssets().open( file
) );
233 catch( IOException e
) { return new HashMap
<String
,String
>(); }
236 private final String
readFileString( File file
)
240 FileInputStream in
= new FileInputStream( file
);
241 BufferedReader reader
= new BufferedReader( new InputStreamReader( in
, "UTF-8" ));
242 return reader
.readLine();
244 catch( IOException e
) { return null; }
247 private final void copyAssetFile( String src
)
249 File dest
= new File( getFilesDir(), src
);
252 Log
.i( LOGTAG
, "extracting " + dest
);
253 dest
.getParentFile().mkdirs();
255 if (dest
.createNewFile())
257 InputStream in
= getAssets().open( src
);
258 FileOutputStream out
= new FileOutputStream( dest
);
260 byte[] buffer
= new byte[65536];
262 while ((read
= in
.read( buffer
)) > 0) out
.write( buffer
, 0, read
);
264 if (isFileExecutable( src
)) dest
.setExecutable( true, true );
267 Log
.i( LOGTAG
, "Failed to create file " + dest
);
269 catch( IOException e
)
271 Log
.i( LOGTAG
, "Failed to copy asset file to " + dest
);
276 private final void deleteAssetFile( String src
)
278 File dest
= new File( getFilesDir(), src
);
279 Log
.i( LOGTAG
, "deleting " + dest
);
283 private final void copyAssetFiles()
285 String new_sum
= readMapFromAssetFile( "sums.sum" ).get( "files.sum" );
286 if (new_sum
== null) return; // no assets
288 SharedPreferences prefs
= PreferenceManager
.getDefaultSharedPreferences( this );
289 String old_sum
= prefs
.getString( "files.sum", "" );
290 if (old_sum
.equals( new_sum
)) return; // no change
291 prefs
.edit().putString( "files.sum", new_sum
).apply();
293 HashMap
<String
,String
> existing_files
= readMapFromDiskFile( "files.sum" );
294 HashMap
<String
,String
> new_files
= readMapFromAssetFile( "files.sum" );
295 ArrayList
<String
> copy_files
= new ArrayList
<String
>();
296 copy_files
.add( "files.sum" );
298 for (Map
.Entry
<String
, String
> entry
: new_files
.entrySet())
300 String name
= entry
.getKey();
301 if (!entry
.getValue().equals( existing_files
.remove( name
))) copy_files
.add( name
);
304 createProgressDialog( copy_files
.size(), "Extracting files..." );
306 for (String name
: existing_files
.keySet()) deleteAssetFile( name
);
308 for (String name
: copy_files
)
310 copyAssetFile( name
);
311 runOnUiThread( new Runnable() { public void run() {
312 progress_dialog
.incrementProgressBy( 1 ); }});
317 // Generic Wine window class
320 private HashMap
<Integer
,WineWindow
> win_map
= new HashMap
<Integer
,WineWindow
>();
322 protected class WineWindow
324 static protected final int HWND_MESSAGE
= 0xfffffffd;
325 static protected final int SWP_NOZORDER
= 0x04;
326 static protected final int WS_VISIBLE
= 0x10000000;
331 protected float scale
;
332 protected boolean visible
;
333 protected Rect visible_rect
;
334 protected Rect client_rect
;
335 protected WineWindow parent
;
336 protected ArrayList
<WineWindow
> children
;
337 protected Surface window_surface
;
338 protected Surface client_surface
;
339 protected SurfaceTexture window_surftex
;
340 protected SurfaceTexture client_surftex
;
341 protected WineWindowGroup window_group
;
342 protected WineWindowGroup client_group
;
344 public WineWindow( int w
, WineWindow parent
, float scale
)
346 Log
.i( LOGTAG
, String
.format( "create hwnd %08x", w
));
351 visible_rect
= client_rect
= new Rect( 0, 0, 0, 0 );
352 this.parent
= parent
;
354 children
= new ArrayList
<WineWindow
>();
355 win_map
.put( w
, this );
356 if (parent
!= null) parent
.children
.add( this );
359 public void destroy()
361 Log
.i( LOGTAG
, String
.format( "destroy hwnd %08x", hwnd
));
363 win_map
.remove( this );
364 if (parent
!= null) parent
.children
.remove( this );
365 destroy_window_groups();
368 public WineWindowGroup
create_window_groups()
370 if (client_group
!= null) return client_group
;
371 window_group
= new WineWindowGroup( this );
372 client_group
= new WineWindowGroup( this );
373 window_group
.addView( client_group
);
374 client_group
.set_layout( client_rect
.left
- visible_rect
.left
,
375 client_rect
.top
- visible_rect
.top
,
376 client_rect
.right
- visible_rect
.left
,
377 client_rect
.bottom
- visible_rect
.top
);
380 parent
.create_window_groups();
381 if (visible
) add_view_to_parent();
382 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
383 visible_rect
.right
, visible_rect
.bottom
);
388 public void destroy_window_groups()
390 if (window_group
!= null)
392 if (parent
!= null && parent
.client_group
!= null) remove_view_from_parent();
393 window_group
.destroy_view();
395 if (client_group
!= null) client_group
.destroy_view();
400 public View
create_whole_view()
402 if (window_group
== null) create_window_groups();
403 window_group
.create_view( false ).layout( 0, 0,
404 Math
.round( (visible_rect
.right
- visible_rect
.left
) * scale
),
405 Math
.round( (visible_rect
.bottom
- visible_rect
.top
) * scale
));
406 window_group
.set_scale( scale
);
410 public void create_client_view()
412 if (client_group
== null) create_window_groups();
413 Log
.i( LOGTAG
, String
.format( "creating client view %08x %s", hwnd
, client_rect
));
414 client_group
.create_view( true ).layout( 0, 0, client_rect
.right
- client_rect
.left
,
415 client_rect
.bottom
- client_rect
.top
);
418 protected void add_view_to_parent()
420 int pos
= parent
.client_group
.getChildCount() - 1;
422 // the content view is always last
423 if (pos
>= 0 && parent
.client_group
.getChildAt( pos
) == parent
.client_group
.get_content_view()) pos
--;
425 for (int i
= 0; i
< parent
.children
.size() && pos
>= 0; i
++)
427 WineWindow child
= parent
.children
.get( i
);
428 if (child
== this) break;
429 if (!child
.visible
) continue;
430 if (child
== ((WineWindowGroup
)parent
.client_group
.getChildAt( pos
)).get_window()) pos
--;
432 parent
.client_group
.addView( window_group
, pos
+ 1 );
435 protected void remove_view_from_parent()
437 parent
.client_group
.removeView( window_group
);
440 protected void set_zorder( WineWindow prev
)
444 parent
.children
.remove( this );
445 if (prev
!= null) pos
= parent
.children
.indexOf( prev
);
446 parent
.children
.add( pos
+ 1, this );
449 protected void sync_views_zorder()
453 for (i
= parent
.children
.size() - 1, j
= 0; i
>= 0; i
--)
455 WineWindow child
= parent
.children
.get( i
);
456 if (!child
.visible
) continue;
457 View child_view
= parent
.client_group
.getChildAt( j
);
458 if (child_view
== parent
.client_group
.get_content_view()) continue;
459 if (child
!= ((WineWindowGroup
)child_view
).get_window()) break;
464 WineWindow child
= parent
.children
.get( i
-- );
465 if (child
.visible
) child
.window_group
.bringToFront();
469 public void pos_changed( int flags
, int insert_after
, int owner
, int style
,
470 Rect window_rect
, Rect client_rect
, Rect visible_rect
)
472 boolean was_visible
= visible
;
473 this.visible_rect
= visible_rect
;
474 this.client_rect
= client_rect
;
477 visible
= (style
& WS_VISIBLE
) != 0;
479 Log
.i( LOGTAG
, String
.format( "pos changed hwnd %08x after %08x owner %08x style %08x win %s client %s visible %s flags %08x",
480 hwnd
, insert_after
, owner
, style
, window_rect
, client_rect
, visible_rect
, flags
));
482 if ((flags
& SWP_NOZORDER
) == 0 && parent
!= null) set_zorder( get_window( insert_after
));
484 if (window_group
!= null)
486 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
487 visible_rect
.right
, visible_rect
.bottom
);
490 if (!was_visible
&& (style
& WS_VISIBLE
) != 0) add_view_to_parent();
491 else if (was_visible
&& (style
& WS_VISIBLE
) == 0) remove_view_from_parent();
492 else if (visible
&& (flags
& SWP_NOZORDER
) == 0) sync_views_zorder();
496 if (client_group
!= null)
497 client_group
.set_layout( client_rect
.left
- visible_rect
.left
,
498 client_rect
.top
- visible_rect
.top
,
499 client_rect
.right
- visible_rect
.left
,
500 client_rect
.bottom
- visible_rect
.top
);
503 public void set_parent( WineWindow new_parent
, float scale
)
505 Log
.i( LOGTAG
, String
.format( "set parent hwnd %08x parent %08x -> %08x",
506 hwnd
, parent
.hwnd
, new_parent
.hwnd
));
508 if (window_group
!= null)
510 if (visible
) remove_view_from_parent();
511 new_parent
.create_window_groups();
512 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
513 visible_rect
.right
, visible_rect
.bottom
);
515 parent
.children
.remove( this );
517 parent
.children
.add( this );
518 if (visible
&& window_group
!= null) add_view_to_parent();
521 public int get_hwnd()
526 private void update_surface( boolean is_client
)
530 Log
.i( LOGTAG
, String
.format( "set client surface hwnd %08x %s", hwnd
, client_surface
));
531 if (client_surface
!= null) wine_surface_changed( hwnd
, client_surface
, true );
535 Log
.i( LOGTAG
, String
.format( "set window surface hwnd %08x %s", hwnd
, window_surface
));
536 if (window_surface
!= null) wine_surface_changed( hwnd
, window_surface
, false );
540 public void set_surface( SurfaceTexture surftex
, boolean is_client
)
544 if (surftex
== null) client_surface
= null;
545 else if (surftex
!= client_surftex
)
547 client_surftex
= surftex
;
548 client_surface
= new Surface( surftex
);
553 if (surftex
== null) window_surface
= null;
554 else if (surftex
!= window_surftex
)
556 window_surftex
= surftex
;
557 window_surface
= new Surface( surftex
);
560 update_surface( is_client
);
563 public void get_event_pos( MotionEvent event
, int[] pos
)
565 pos
[0] = Math
.round( event
.getX() * scale
+ window_group
.getLeft() );
566 pos
[1] = Math
.round( event
.getY() * scale
+ window_group
.getTop() );
571 // Window group for a Wine window, optionally containing a content view
574 protected class WineWindowGroup
extends ViewGroup
576 private WineView content_view
;
577 private WineWindow win
;
579 WineWindowGroup( WineWindow win
)
581 super( WineActivity
.this );
583 setVisibility( View
.VISIBLE
);
586 /* wrapper for layout() making sure that the view is not empty */
587 public void set_layout( int left
, int top
, int right
, int bottom
)
593 if (right
<= left
+ 1) right
= left
+ 2;
594 if (bottom
<= top
+ 1) bottom
= top
+ 2;
595 layout( left
, top
, right
, bottom
);
599 protected void onLayout( boolean changed
, int left
, int top
, int right
, int bottom
)
601 if (content_view
!= null) content_view
.layout( 0, 0, right
- left
, bottom
- top
);
604 public void set_scale( float scale
)
606 if (content_view
== null) return;
607 content_view
.setPivotX( 0 );
608 content_view
.setPivotY( 0 );
609 content_view
.setScaleX( scale
);
610 content_view
.setScaleY( scale
);
613 public WineView
create_view( boolean is_client
)
615 if (content_view
!= null) return content_view
;
616 content_view
= new WineView( WineActivity
.this, win
, is_client
);
617 addView( content_view
);
620 content_view
.setFocusable( true );
621 content_view
.setFocusableInTouchMode( true );
626 public void destroy_view()
628 if (content_view
== null) return;
629 removeView( content_view
);
633 public WineView
get_content_view()
638 public WineWindow
get_window()
644 // View used for all Wine windows, backed by a TextureView
646 protected class WineView
extends TextureView
implements TextureView
.SurfaceTextureListener
648 private WineWindow window
;
649 private boolean is_client
;
651 public WineView( Context c
, WineWindow win
, boolean client
)
656 setSurfaceTextureListener( this );
657 setVisibility( VISIBLE
);
659 setFocusable( true );
660 setFocusableInTouchMode( true );
663 public WineWindow
get_window()
669 public void onSurfaceTextureAvailable( SurfaceTexture surftex
, int width
, int height
)
671 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureAvailable win %08x %dx%d %s",
672 window
.hwnd
, width
, height
, is_client ?
"client" : "whole" ));
673 window
.set_surface( surftex
, is_client
);
677 public void onSurfaceTextureSizeChanged( SurfaceTexture surftex
, int width
, int height
)
679 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureSizeChanged win %08x %dx%d %s",
680 window
.hwnd
, width
, height
, is_client ?
"client" : "whole" ));
681 window
.set_surface( surftex
, is_client
);
685 public boolean onSurfaceTextureDestroyed( SurfaceTexture surftex
)
687 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureDestroyed win %08x %s",
688 window
.hwnd
, is_client ?
"client" : "whole" ));
689 window
.set_surface( null, is_client
);
690 return false; // hold on to the texture since the app may still be using it
694 public void onSurfaceTextureUpdated(SurfaceTexture surftex
)
699 public PointerIcon
onResolvePointerIcon( MotionEvent event
, int index
)
701 return current_cursor
;
705 public boolean onGenericMotionEvent( MotionEvent event
)
707 if (is_client
) return false; // let the whole window handle it
708 if (window
.parent
!= null && window
.parent
!= desktop_window
) return false; // let the parent handle it
710 if ((event
.getSource() & InputDevice
.SOURCE_CLASS_POINTER
) != 0)
712 int[] pos
= new int[2];
713 window
.get_event_pos( event
, pos
);
714 Log
.i( LOGTAG
, String
.format( "view motion event win %08x action %d pos %d,%d buttons %04x view %d,%d",
715 window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
716 event
.getButtonState(), getLeft(), getTop() ));
717 return wine_motion_event( window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
718 event
.getButtonState(), (int)event
.getAxisValue(MotionEvent
.AXIS_VSCROLL
) );
720 return super.onGenericMotionEvent(event
);
724 public boolean onTouchEvent( MotionEvent event
)
726 if (is_client
) return false; // let the whole window handle it
727 if (window
.parent
!= null && window
.parent
!= desktop_window
) return false; // let the parent handle it
729 int[] pos
= new int[2];
730 window
.get_event_pos( event
, pos
);
731 Log
.i( LOGTAG
, String
.format( "view touch event win %08x action %d pos %d,%d buttons %04x view %d,%d",
732 window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
733 event
.getButtonState(), getLeft(), getTop() ));
734 return wine_motion_event( window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
735 event
.getButtonState(), 0 );
739 public boolean dispatchKeyEvent( KeyEvent event
)
741 Log
.i( LOGTAG
, String
.format( "view key event win %08x action %d keycode %d (%s)",
742 window
.hwnd
, event
.getAction(), event
.getKeyCode(),
743 KeyEvent
.keyCodeToString( event
.getKeyCode() )));;
744 boolean ret
= wine_keyboard_event( window
.hwnd
, event
.getAction(), event
.getKeyCode(),
745 event
.getMetaState() );
746 if (!ret
) ret
= super.dispatchKeyEvent(event
);
751 // The top-level desktop view group
753 protected class TopView
extends ViewGroup
755 public TopView( Context context
, int hwnd
)
758 desktop_window
= new WineWindow( hwnd
, null, 1.0f
);
759 addView( desktop_window
.create_whole_view() );
760 desktop_window
.client_group
.bringToFront();
762 message_window
= new WineWindow( WineWindow
.HWND_MESSAGE
, null, 1.0f
);
763 message_window
.create_window_groups();
767 protected void onSizeChanged( int width
, int height
, int old_width
, int old_height
)
769 Log
.i( LOGTAG
, String
.format( "desktop size %dx%d", width
, height
));
770 wine_desktop_changed( width
, height
);
774 protected void onLayout( boolean changed
, int left
, int top
, int right
, int bottom
)
780 protected WineWindow
get_window( int hwnd
)
782 return win_map
.get( hwnd
);
785 // Entry points for the device driver
787 public void create_desktop_window( int hwnd
)
789 Log
.i( LOGTAG
, String
.format( "create desktop view %08x", hwnd
));
790 setContentView( new TopView( this, hwnd
));
791 progress_dialog
.dismiss();
792 wine_config_changed( getResources().getConfiguration().densityDpi
);
795 public void create_window( int hwnd
, boolean opengl
, int parent
, float scale
, int pid
)
797 WineWindow win
= get_window( hwnd
);
800 win
= new WineWindow( hwnd
, get_window( parent
), scale
);
801 win
.create_window_groups();
802 if (win
.parent
== desktop_window
) win
.create_whole_view();
804 if (opengl
) win
.create_client_view();
807 public void destroy_window( int hwnd
)
809 WineWindow win
= get_window( hwnd
);
810 if (win
!= null) win
.destroy();
813 public void set_window_parent( int hwnd
, int parent
, float scale
, int pid
)
815 WineWindow win
= get_window( hwnd
);
816 if (win
== null) return;
817 win
.set_parent( get_window( parent
), scale
);
818 if (win
.parent
== desktop_window
) win
.create_whole_view();
822 public void set_cursor( int id
, int width
, int height
, int hotspotx
, int hotspoty
, int bits
[] )
824 Log
.i( LOGTAG
, String
.format( "set_cursor id %d size %dx%d hotspot %dx%d", id
, width
, height
, hotspotx
, hotspoty
));
827 Bitmap bitmap
= Bitmap
.createBitmap( bits
, width
, height
, Bitmap
.Config
.ARGB_8888
);
828 current_cursor
= PointerIcon
.create( bitmap
, hotspotx
, hotspoty
);
830 else current_cursor
= PointerIcon
.getSystemIcon( this, id
);
833 public void window_pos_changed( int hwnd
, int flags
, int insert_after
, int owner
, int style
,
834 Rect window_rect
, Rect client_rect
, Rect visible_rect
)
836 WineWindow win
= get_window( hwnd
);
838 win
.pos_changed( flags
, insert_after
, owner
, style
, window_rect
, client_rect
, visible_rect
);
841 public void createDesktopWindow( final int hwnd
)
843 runOnUiThread( new Runnable() { public void run() { create_desktop_window( hwnd
); }} );
846 public void createWindow( final int hwnd
, final boolean opengl
, final int parent
, final float scale
, final int pid
)
848 runOnUiThread( new Runnable() { public void run() { create_window( hwnd
, opengl
, parent
, scale
, pid
); }} );
851 public void destroyWindow( final int hwnd
)
853 runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd
); }} );
856 public void setParent( final int hwnd
, final int parent
, final float scale
, final int pid
)
858 runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd
, parent
, scale
, pid
); }} );
861 public void setCursor( final int id
, final int width
, final int height
,
862 final int hotspotx
, final int hotspoty
, final int bits
[] )
864 if (Build
.VERSION
.SDK_INT
< 24) return;
865 runOnUiThread( new Runnable() { public void run() { set_cursor( id
, width
, height
, hotspotx
, hotspoty
, bits
); }} );
868 public void windowPosChanged( final int hwnd
, final int flags
, final int insert_after
,
869 final int owner
, final int style
,
870 final int window_left
, final int window_top
,
871 final int window_right
, final int window_bottom
,
872 final int client_left
, final int client_top
,
873 final int client_right
, final int client_bottom
,
874 final int visible_left
, final int visible_top
,
875 final int visible_right
, final int visible_bottom
)
877 final Rect window_rect
= new Rect( window_left
, window_top
, window_right
, window_bottom
);
878 final Rect client_rect
= new Rect( client_left
, client_top
, client_right
, client_bottom
);
879 final Rect visible_rect
= new Rect( visible_left
, visible_top
, visible_right
, visible_bottom
);
880 runOnUiThread( new Runnable() {
881 public void run() { window_pos_changed( hwnd
, flags
, insert_after
, owner
, style
,
882 window_rect
, client_rect
, visible_rect
); }} );