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..." );
143 System
.loadLibrary( "wine" );
145 catch (java
.lang
.UnsatisfiedLinkError e
)
147 System
.load( libdir
.toString() + "/libwine.so" );
151 runWine( cmdline
, env
);
154 private final void runWine( String cmdline
, HashMap
<String
,String
> environ
)
156 String
[] env
= new String
[environ
.size() * 2];
158 for (Map
.Entry
<String
,String
> entry
: environ
.entrySet())
160 env
[j
++] = entry
.getKey();
161 env
[j
++] = entry
.getValue();
164 String
[] cmd
= { environ
.get( "WINELOADER" ),
166 "/desktop=shell,,android",
169 String err
= wine_init( cmd
, env
);
170 Log
.e( LOGTAG
, err
);
173 private void createProgressDialog( final int max
, final String message
)
175 runOnUiThread( new Runnable() { public void run() {
176 if (progress_dialog
!= null) progress_dialog
.dismiss();
177 progress_dialog
= new ProgressDialog( WineActivity
.this );
178 progress_dialog
.setProgressStyle( max
> 0 ? ProgressDialog
.STYLE_HORIZONTAL
179 : ProgressDialog
.STYLE_SPINNER
);
180 progress_dialog
.setTitle( "Wine" );
181 progress_dialog
.setMessage( message
);
182 progress_dialog
.setCancelable( false );
183 progress_dialog
.setMax( max
);
184 progress_dialog
.show();
189 private final boolean isFileWanted( String name
)
191 if (name
.equals( "files.sum" )) return true;
192 if (name
.startsWith( "share/" )) return true;
193 for (String abi
: get_supported_abis())
195 if (name
.startsWith( abi
+ "/system/" )) return false;
196 if (name
.startsWith( abi
+ "/" )) return true;
198 if (name
.startsWith( "x86/" )) return true;
202 private final boolean isFileExecutable( String name
)
204 return !name
.equals( "files.sum" ) && !name
.startsWith( "share/" );
207 private final HashMap
<String
,String
> readMapFromInputStream( InputStream in
)
209 HashMap
<String
,String
> map
= new HashMap
<String
,String
>();
214 BufferedReader reader
= new BufferedReader( new InputStreamReader( in
, "UTF-8" ));
215 while ((str
= reader
.readLine()) != null)
217 String entry
[] = str
.split( "\\s+", 2 );
218 if (entry
.length
== 2 && isFileWanted( entry
[1] )) map
.put( entry
[1], entry
[0] );
221 catch( IOException e
) { }
225 private final HashMap
<String
,String
> readMapFromDiskFile( String file
)
229 return readMapFromInputStream( new FileInputStream( new File( getFilesDir(), file
)));
231 catch( IOException e
) { return new HashMap
<String
,String
>(); }
234 private final HashMap
<String
,String
> readMapFromAssetFile( String file
)
238 return readMapFromInputStream( getAssets().open( file
) );
240 catch( IOException e
) { return new HashMap
<String
,String
>(); }
243 private final String
readFileString( File file
)
247 FileInputStream in
= new FileInputStream( file
);
248 BufferedReader reader
= new BufferedReader( new InputStreamReader( in
, "UTF-8" ));
249 return reader
.readLine();
251 catch( IOException e
) { return null; }
254 private final void copyAssetFile( String src
)
256 File dest
= new File( getFilesDir(), src
);
259 Log
.i( LOGTAG
, "extracting " + dest
);
260 dest
.getParentFile().mkdirs();
262 if (dest
.createNewFile())
264 InputStream in
= getAssets().open( src
);
265 FileOutputStream out
= new FileOutputStream( dest
);
267 byte[] buffer
= new byte[65536];
269 while ((read
= in
.read( buffer
)) > 0) out
.write( buffer
, 0, read
);
271 if (isFileExecutable( src
)) dest
.setExecutable( true, true );
274 Log
.i( LOGTAG
, "Failed to create file " + dest
);
276 catch( IOException e
)
278 Log
.i( LOGTAG
, "Failed to copy asset file to " + dest
);
283 private final void deleteAssetFile( String src
)
285 File dest
= new File( getFilesDir(), src
);
286 Log
.i( LOGTAG
, "deleting " + dest
);
290 private final void copyAssetFiles()
292 String new_sum
= readMapFromAssetFile( "sums.sum" ).get( "files.sum" );
293 if (new_sum
== null) return; // no assets
295 SharedPreferences prefs
= PreferenceManager
.getDefaultSharedPreferences( this );
296 String old_sum
= prefs
.getString( "files.sum", "" );
297 if (old_sum
.equals( new_sum
)) return; // no change
298 prefs
.edit().putString( "files.sum", new_sum
).apply();
300 HashMap
<String
,String
> existing_files
= readMapFromDiskFile( "files.sum" );
301 HashMap
<String
,String
> new_files
= readMapFromAssetFile( "files.sum" );
302 ArrayList
<String
> copy_files
= new ArrayList
<String
>();
303 copy_files
.add( "files.sum" );
305 for (Map
.Entry
<String
, String
> entry
: new_files
.entrySet())
307 String name
= entry
.getKey();
308 if (!entry
.getValue().equals( existing_files
.remove( name
))) copy_files
.add( name
);
311 createProgressDialog( copy_files
.size(), "Extracting files..." );
313 for (String name
: existing_files
.keySet()) deleteAssetFile( name
);
315 for (String name
: copy_files
)
317 copyAssetFile( name
);
318 runOnUiThread( new Runnable() { public void run() {
319 progress_dialog
.incrementProgressBy( 1 ); }});
324 // Generic Wine window class
327 private HashMap
<Integer
,WineWindow
> win_map
= new HashMap
<Integer
,WineWindow
>();
329 protected class WineWindow
331 static protected final int HWND_MESSAGE
= 0xfffffffd;
332 static protected final int SWP_NOZORDER
= 0x04;
333 static protected final int WS_VISIBLE
= 0x10000000;
338 protected float scale
;
339 protected boolean visible
;
340 protected Rect visible_rect
;
341 protected Rect client_rect
;
342 protected WineWindow parent
;
343 protected ArrayList
<WineWindow
> children
;
344 protected Surface window_surface
;
345 protected Surface client_surface
;
346 protected SurfaceTexture window_surftex
;
347 protected SurfaceTexture client_surftex
;
348 protected WineWindowGroup window_group
;
349 protected WineWindowGroup client_group
;
351 public WineWindow( int w
, WineWindow parent
, float scale
)
353 Log
.i( LOGTAG
, String
.format( "create hwnd %08x", w
));
358 visible_rect
= client_rect
= new Rect( 0, 0, 0, 0 );
359 this.parent
= parent
;
361 children
= new ArrayList
<WineWindow
>();
362 win_map
.put( w
, this );
363 if (parent
!= null) parent
.children
.add( this );
366 public void destroy()
368 Log
.i( LOGTAG
, String
.format( "destroy hwnd %08x", hwnd
));
370 win_map
.remove( this );
371 if (parent
!= null) parent
.children
.remove( this );
372 destroy_window_groups();
375 public WineWindowGroup
create_window_groups()
377 if (client_group
!= null) return client_group
;
378 window_group
= new WineWindowGroup( this );
379 client_group
= new WineWindowGroup( this );
380 window_group
.addView( client_group
);
381 client_group
.set_layout( client_rect
.left
- visible_rect
.left
,
382 client_rect
.top
- visible_rect
.top
,
383 client_rect
.right
- visible_rect
.left
,
384 client_rect
.bottom
- visible_rect
.top
);
387 parent
.create_window_groups();
388 if (visible
) add_view_to_parent();
389 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
390 visible_rect
.right
, visible_rect
.bottom
);
395 public void destroy_window_groups()
397 if (window_group
!= null)
399 if (parent
!= null && parent
.client_group
!= null) remove_view_from_parent();
400 window_group
.destroy_view();
402 if (client_group
!= null) client_group
.destroy_view();
407 public View
create_whole_view()
409 if (window_group
== null) create_window_groups();
410 window_group
.create_view( false ).layout( 0, 0,
411 Math
.round( (visible_rect
.right
- visible_rect
.left
) * scale
),
412 Math
.round( (visible_rect
.bottom
- visible_rect
.top
) * scale
));
413 window_group
.set_scale( scale
);
417 public void create_client_view()
419 if (client_group
== null) create_window_groups();
420 Log
.i( LOGTAG
, String
.format( "creating client view %08x %s", hwnd
, client_rect
));
421 client_group
.create_view( true ).layout( 0, 0, client_rect
.right
- client_rect
.left
,
422 client_rect
.bottom
- client_rect
.top
);
425 protected void add_view_to_parent()
427 int pos
= parent
.client_group
.getChildCount() - 1;
429 // the content view is always last
430 if (pos
>= 0 && parent
.client_group
.getChildAt( pos
) == parent
.client_group
.get_content_view()) pos
--;
432 for (int i
= 0; i
< parent
.children
.size() && pos
>= 0; i
++)
434 WineWindow child
= parent
.children
.get( i
);
435 if (child
== this) break;
436 if (!child
.visible
) continue;
437 if (child
== ((WineWindowGroup
)parent
.client_group
.getChildAt( pos
)).get_window()) pos
--;
439 parent
.client_group
.addView( window_group
, pos
+ 1 );
442 protected void remove_view_from_parent()
444 parent
.client_group
.removeView( window_group
);
447 protected void set_zorder( WineWindow prev
)
451 parent
.children
.remove( this );
452 if (prev
!= null) pos
= parent
.children
.indexOf( prev
);
453 parent
.children
.add( pos
+ 1, this );
456 protected void sync_views_zorder()
460 for (i
= parent
.children
.size() - 1, j
= 0; i
>= 0; i
--)
462 WineWindow child
= parent
.children
.get( i
);
463 if (!child
.visible
) continue;
464 View child_view
= parent
.client_group
.getChildAt( j
);
465 if (child_view
== parent
.client_group
.get_content_view()) continue;
466 if (child
!= ((WineWindowGroup
)child_view
).get_window()) break;
471 WineWindow child
= parent
.children
.get( i
-- );
472 if (child
.visible
) child
.window_group
.bringToFront();
476 public void pos_changed( int flags
, int insert_after
, int owner
, int style
,
477 Rect window_rect
, Rect client_rect
, Rect visible_rect
)
479 boolean was_visible
= visible
;
480 this.visible_rect
= visible_rect
;
481 this.client_rect
= client_rect
;
484 visible
= (style
& WS_VISIBLE
) != 0;
486 Log
.i( LOGTAG
, String
.format( "pos changed hwnd %08x after %08x owner %08x style %08x win %s client %s visible %s flags %08x",
487 hwnd
, insert_after
, owner
, style
, window_rect
, client_rect
, visible_rect
, flags
));
489 if ((flags
& SWP_NOZORDER
) == 0 && parent
!= null) set_zorder( get_window( insert_after
));
491 if (window_group
!= null)
493 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
494 visible_rect
.right
, visible_rect
.bottom
);
497 if (!was_visible
&& (style
& WS_VISIBLE
) != 0) add_view_to_parent();
498 else if (was_visible
&& (style
& WS_VISIBLE
) == 0) remove_view_from_parent();
499 else if (visible
&& (flags
& SWP_NOZORDER
) == 0) sync_views_zorder();
503 if (client_group
!= null)
504 client_group
.set_layout( client_rect
.left
- visible_rect
.left
,
505 client_rect
.top
- visible_rect
.top
,
506 client_rect
.right
- visible_rect
.left
,
507 client_rect
.bottom
- visible_rect
.top
);
510 public void set_parent( WineWindow new_parent
, float scale
)
512 Log
.i( LOGTAG
, String
.format( "set parent hwnd %08x parent %08x -> %08x",
513 hwnd
, parent
.hwnd
, new_parent
.hwnd
));
515 if (window_group
!= null)
517 if (visible
) remove_view_from_parent();
518 new_parent
.create_window_groups();
519 window_group
.set_layout( visible_rect
.left
, visible_rect
.top
,
520 visible_rect
.right
, visible_rect
.bottom
);
522 parent
.children
.remove( this );
524 parent
.children
.add( this );
525 if (visible
&& window_group
!= null) add_view_to_parent();
528 public int get_hwnd()
533 private void update_surface( boolean is_client
)
537 Log
.i( LOGTAG
, String
.format( "set client surface hwnd %08x %s", hwnd
, client_surface
));
538 if (client_surface
!= null) wine_surface_changed( hwnd
, client_surface
, true );
542 Log
.i( LOGTAG
, String
.format( "set window surface hwnd %08x %s", hwnd
, window_surface
));
543 if (window_surface
!= null) wine_surface_changed( hwnd
, window_surface
, false );
547 public void set_surface( SurfaceTexture surftex
, boolean is_client
)
551 if (surftex
== null) client_surface
= null;
552 else if (surftex
!= client_surftex
)
554 client_surftex
= surftex
;
555 client_surface
= new Surface( surftex
);
560 if (surftex
== null) window_surface
= null;
561 else if (surftex
!= window_surftex
)
563 window_surftex
= surftex
;
564 window_surface
= new Surface( surftex
);
567 update_surface( is_client
);
570 public void get_event_pos( MotionEvent event
, int[] pos
)
572 pos
[0] = Math
.round( event
.getX() * scale
+ window_group
.getLeft() );
573 pos
[1] = Math
.round( event
.getY() * scale
+ window_group
.getTop() );
578 // Window group for a Wine window, optionally containing a content view
581 protected class WineWindowGroup
extends ViewGroup
583 private WineView content_view
;
584 private WineWindow win
;
586 WineWindowGroup( WineWindow win
)
588 super( WineActivity
.this );
590 setVisibility( View
.VISIBLE
);
593 /* wrapper for layout() making sure that the view is not empty */
594 public void set_layout( int left
, int top
, int right
, int bottom
)
600 if (right
<= left
+ 1) right
= left
+ 2;
601 if (bottom
<= top
+ 1) bottom
= top
+ 2;
602 layout( left
, top
, right
, bottom
);
606 protected void onLayout( boolean changed
, int left
, int top
, int right
, int bottom
)
608 if (content_view
!= null) content_view
.layout( 0, 0, right
- left
, bottom
- top
);
611 public void set_scale( float scale
)
613 if (content_view
== null) return;
614 content_view
.setPivotX( 0 );
615 content_view
.setPivotY( 0 );
616 content_view
.setScaleX( scale
);
617 content_view
.setScaleY( scale
);
620 public WineView
create_view( boolean is_client
)
622 if (content_view
!= null) return content_view
;
623 content_view
= new WineView( WineActivity
.this, win
, is_client
);
624 addView( content_view
);
627 content_view
.setFocusable( true );
628 content_view
.setFocusableInTouchMode( true );
633 public void destroy_view()
635 if (content_view
== null) return;
636 removeView( content_view
);
640 public WineView
get_content_view()
645 public WineWindow
get_window()
651 // View used for all Wine windows, backed by a TextureView
653 protected class WineView
extends TextureView
implements TextureView
.SurfaceTextureListener
655 private WineWindow window
;
656 private boolean is_client
;
658 public WineView( Context c
, WineWindow win
, boolean client
)
663 setSurfaceTextureListener( this );
664 setVisibility( VISIBLE
);
666 setFocusable( true );
667 setFocusableInTouchMode( true );
670 public WineWindow
get_window()
676 public void onSurfaceTextureAvailable( SurfaceTexture surftex
, int width
, int height
)
678 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureAvailable win %08x %dx%d %s",
679 window
.hwnd
, width
, height
, is_client ?
"client" : "whole" ));
680 window
.set_surface( surftex
, is_client
);
684 public void onSurfaceTextureSizeChanged( SurfaceTexture surftex
, int width
, int height
)
686 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureSizeChanged win %08x %dx%d %s",
687 window
.hwnd
, width
, height
, is_client ?
"client" : "whole" ));
688 window
.set_surface( surftex
, is_client
);
692 public boolean onSurfaceTextureDestroyed( SurfaceTexture surftex
)
694 Log
.i( LOGTAG
, String
.format( "onSurfaceTextureDestroyed win %08x %s",
695 window
.hwnd
, is_client ?
"client" : "whole" ));
696 window
.set_surface( null, is_client
);
697 return false; // hold on to the texture since the app may still be using it
701 public void onSurfaceTextureUpdated(SurfaceTexture surftex
)
706 public PointerIcon
onResolvePointerIcon( MotionEvent event
, int index
)
708 return current_cursor
;
712 public boolean onGenericMotionEvent( MotionEvent event
)
714 if (is_client
) return false; // let the whole window handle it
715 if (window
.parent
!= null && window
.parent
!= desktop_window
) return false; // let the parent handle it
717 if ((event
.getSource() & InputDevice
.SOURCE_CLASS_POINTER
) != 0)
719 int[] pos
= new int[2];
720 window
.get_event_pos( event
, pos
);
721 Log
.i( LOGTAG
, String
.format( "view motion event win %08x action %d pos %d,%d buttons %04x view %d,%d",
722 window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
723 event
.getButtonState(), getLeft(), getTop() ));
724 return wine_motion_event( window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
725 event
.getButtonState(), (int)event
.getAxisValue(MotionEvent
.AXIS_VSCROLL
) );
727 return super.onGenericMotionEvent(event
);
731 public boolean onTouchEvent( MotionEvent event
)
733 if (is_client
) return false; // let the whole window handle it
734 if (window
.parent
!= null && window
.parent
!= desktop_window
) return false; // let the parent handle it
736 int[] pos
= new int[2];
737 window
.get_event_pos( event
, pos
);
738 Log
.i( LOGTAG
, String
.format( "view touch event win %08x action %d pos %d,%d buttons %04x view %d,%d",
739 window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
740 event
.getButtonState(), getLeft(), getTop() ));
741 return wine_motion_event( window
.hwnd
, event
.getAction(), pos
[0], pos
[1],
742 event
.getButtonState(), 0 );
746 public boolean dispatchKeyEvent( KeyEvent event
)
748 Log
.i( LOGTAG
, String
.format( "view key event win %08x action %d keycode %d (%s)",
749 window
.hwnd
, event
.getAction(), event
.getKeyCode(),
750 KeyEvent
.keyCodeToString( event
.getKeyCode() )));;
751 boolean ret
= wine_keyboard_event( window
.hwnd
, event
.getAction(), event
.getKeyCode(),
752 event
.getMetaState() );
753 if (!ret
) ret
= super.dispatchKeyEvent(event
);
758 // The top-level desktop view group
760 protected class TopView
extends ViewGroup
762 public TopView( Context context
, int hwnd
)
765 desktop_window
= new WineWindow( hwnd
, null, 1.0f
);
766 addView( desktop_window
.create_whole_view() );
767 desktop_window
.client_group
.bringToFront();
769 message_window
= new WineWindow( WineWindow
.HWND_MESSAGE
, null, 1.0f
);
770 message_window
.create_window_groups();
774 protected void onSizeChanged( int width
, int height
, int old_width
, int old_height
)
776 Log
.i( LOGTAG
, String
.format( "desktop size %dx%d", width
, height
));
777 wine_desktop_changed( width
, height
);
781 protected void onLayout( boolean changed
, int left
, int top
, int right
, int bottom
)
787 protected WineWindow
get_window( int hwnd
)
789 return win_map
.get( hwnd
);
792 // Entry points for the device driver
794 public void create_desktop_window( int hwnd
)
796 Log
.i( LOGTAG
, String
.format( "create desktop view %08x", hwnd
));
797 setContentView( new TopView( this, hwnd
));
798 progress_dialog
.dismiss();
799 wine_config_changed( getResources().getConfiguration().densityDpi
);
802 public void create_window( int hwnd
, boolean opengl
, int parent
, float scale
, int pid
)
804 WineWindow win
= get_window( hwnd
);
807 win
= new WineWindow( hwnd
, get_window( parent
), scale
);
808 win
.create_window_groups();
809 if (win
.parent
== desktop_window
) win
.create_whole_view();
811 if (opengl
) win
.create_client_view();
814 public void destroy_window( int hwnd
)
816 WineWindow win
= get_window( hwnd
);
817 if (win
!= null) win
.destroy();
820 public void set_window_parent( int hwnd
, int parent
, float scale
, int pid
)
822 WineWindow win
= get_window( hwnd
);
823 if (win
== null) return;
824 win
.set_parent( get_window( parent
), scale
);
825 if (win
.parent
== desktop_window
) win
.create_whole_view();
829 public void set_cursor( int id
, int width
, int height
, int hotspotx
, int hotspoty
, int bits
[] )
831 Log
.i( LOGTAG
, String
.format( "set_cursor id %d size %dx%d hotspot %dx%d", id
, width
, height
, hotspotx
, hotspoty
));
834 Bitmap bitmap
= Bitmap
.createBitmap( bits
, width
, height
, Bitmap
.Config
.ARGB_8888
);
835 current_cursor
= PointerIcon
.create( bitmap
, hotspotx
, hotspoty
);
837 else current_cursor
= PointerIcon
.getSystemIcon( this, id
);
840 public void window_pos_changed( int hwnd
, int flags
, int insert_after
, int owner
, int style
,
841 Rect window_rect
, Rect client_rect
, Rect visible_rect
)
843 WineWindow win
= get_window( hwnd
);
845 win
.pos_changed( flags
, insert_after
, owner
, style
, window_rect
, client_rect
, visible_rect
);
848 public void createDesktopWindow( final int hwnd
)
850 runOnUiThread( new Runnable() { public void run() { create_desktop_window( hwnd
); }} );
853 public void createWindow( final int hwnd
, final boolean opengl
, final int parent
, final float scale
, final int pid
)
855 runOnUiThread( new Runnable() { public void run() { create_window( hwnd
, opengl
, parent
, scale
, pid
); }} );
858 public void destroyWindow( final int hwnd
)
860 runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd
); }} );
863 public void setParent( final int hwnd
, final int parent
, final float scale
, final int pid
)
865 runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd
, parent
, scale
, pid
); }} );
868 public void setCursor( final int id
, final int width
, final int height
,
869 final int hotspotx
, final int hotspoty
, final int bits
[] )
871 if (Build
.VERSION
.SDK_INT
< 24) return;
872 runOnUiThread( new Runnable() { public void run() { set_cursor( id
, width
, height
, hotspotx
, hotspoty
, bits
); }} );
875 public void windowPosChanged( final int hwnd
, final int flags
, final int insert_after
,
876 final int owner
, final int style
,
877 final int window_left
, final int window_top
,
878 final int window_right
, final int window_bottom
,
879 final int client_left
, final int client_top
,
880 final int client_right
, final int client_bottom
,
881 final int visible_left
, final int visible_top
,
882 final int visible_right
, final int visible_bottom
)
884 final Rect window_rect
= new Rect( window_left
, window_top
, window_right
, window_bottom
);
885 final Rect client_rect
= new Rect( client_left
, client_top
, client_right
, client_bottom
);
886 final Rect visible_rect
= new Rect( visible_left
, visible_top
, visible_right
, visible_bottom
);
887 runOnUiThread( new Runnable() {
888 public void run() { window_pos_changed( hwnd
, flags
, insert_after
, owner
, style
,
889 window_rect
, client_rect
, visible_rect
); }} );