mfplat: Add MFCreateAMMediaTypeFromMFMediaType stub.
[wine.git] / dlls / wineandroid.drv / WineActivity.java
bloba47a4f892907d6fc97323490b9276f64e279c460
1 /*
2 * WineActivity class
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;
44 import java.io.File;
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;
53 import java.util.Map;
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;
71 @Override
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();
81 @TargetApi(21)
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" );
97 return null;
100 private String get_so_dir( String abi )
102 if (abi.equals( "x86" )) return "/i386-unix";
103 if (abi.equals( "x86_64" )) return "/x86_64-unix";
104 if (abi.equals( "armeabi-v7a" )) return "/arm-unix";
105 if (abi.equals( "arm64-v8a" )) return "/aarch64-unix";
106 return "";
109 private void loadWine( String cmdline )
111 copyAssetFiles();
113 String wine_abi = get_wine_abi();
114 File bindir = new File( getFilesDir(), wine_abi + "/bin" );
115 File libdir = new File( getFilesDir(), wine_abi + "/lib" );
116 File dlldir = new File( libdir, "wine" );
117 File prefix = new File( getFilesDir(), "prefix" );
118 File loader = new File( bindir, "wine" );
119 String locale = Locale.getDefault().getLanguage() + "_" +
120 Locale.getDefault().getCountry() + ".UTF-8";
122 HashMap<String,String> env = new HashMap<String,String>();
123 env.put( "WINELOADER", loader.toString() );
124 env.put( "WINEPREFIX", prefix.toString() );
125 env.put( "WINEDLLPATH", dlldir.toString() );
126 env.put( "LD_LIBRARY_PATH", libdir.toString() + ":" + getApplicationInfo().nativeLibraryDir );
127 env.put( "LC_ALL", locale );
128 env.put( "LANG", locale );
129 env.put( "PATH", bindir.toString() + ":" + System.getenv( "PATH" ));
131 if (cmdline == null)
133 if (new File( prefix, "drive_c/winestart.cmd" ).exists()) cmdline = "c:\\winestart.cmd";
134 else cmdline = "c:\\windows\\system32\\wineconsole.exe";
137 String winedebug = readFileString( new File( prefix, "winedebug" ));
138 if (winedebug == null) winedebug = readFileString( new File( getFilesDir(), "winedebug" ));
139 if (winedebug != null)
141 File log = new File( getFilesDir(), "log" );
142 env.put( "WINEDEBUG", winedebug );
143 env.put( "WINEDEBUGLOG", log.toString() );
144 Log.i( LOGTAG, "logging to " + log.toString() );
145 log.delete();
148 createProgressDialog( 0, "Setting up the Windows environment..." );
150 System.load( dlldir.toString() + get_so_dir(wine_abi) + "/ntdll.so" );
151 prefix.mkdirs();
153 runWine( cmdline, env );
156 private final void runWine( String cmdline, HashMap<String,String> environ )
158 String[] env = new String[environ.size() * 2];
159 int j = 0;
160 for (Map.Entry<String,String> entry : environ.entrySet())
162 env[j++] = entry.getKey();
163 env[j++] = entry.getValue();
166 String[] cmd = { environ.get( "WINELOADER" ),
167 "c:\\windows\\system32\\explorer.exe",
168 "/desktop=shell,,android",
169 cmdline };
171 String err = wine_init( cmd, env );
172 Log.e( LOGTAG, err );
175 private void createProgressDialog( final int max, final String message )
177 runOnUiThread( new Runnable() { public void run() {
178 if (progress_dialog != null) progress_dialog.dismiss();
179 progress_dialog = new ProgressDialog( WineActivity.this );
180 progress_dialog.setProgressStyle( max > 0 ? ProgressDialog.STYLE_HORIZONTAL
181 : ProgressDialog.STYLE_SPINNER );
182 progress_dialog.setTitle( "Wine" );
183 progress_dialog.setMessage( message );
184 progress_dialog.setCancelable( false );
185 progress_dialog.setMax( max );
186 progress_dialog.show();
187 }});
191 private final boolean isFileWanted( String name )
193 if (name.equals( "files.sum" )) return true;
194 if (name.startsWith( "share/" )) return true;
195 for (String abi : get_supported_abis())
197 if (name.startsWith( abi + "/system/" )) return false;
198 if (name.startsWith( abi + "/" )) return true;
200 if (name.startsWith( "x86/" )) return true;
201 return false;
204 private final boolean isFileExecutable( String name )
206 return !name.equals( "files.sum" ) && !name.startsWith( "share/" );
209 private final HashMap<String,String> readMapFromInputStream( InputStream in )
211 HashMap<String,String> map = new HashMap<String,String>();
212 String str;
216 BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ));
217 while ((str = reader.readLine()) != null)
219 String entry[] = str.split( "\\s+", 2 );
220 if (entry.length == 2 && isFileWanted( entry[1] )) map.put( entry[1], entry[0] );
223 catch( IOException e ) { }
224 return map;
227 private final HashMap<String,String> readMapFromDiskFile( String file )
231 return readMapFromInputStream( new FileInputStream( new File( getFilesDir(), file )));
233 catch( IOException e ) { return new HashMap<String,String>(); }
236 private final HashMap<String,String> readMapFromAssetFile( String file )
240 return readMapFromInputStream( getAssets().open( file ) );
242 catch( IOException e ) { return new HashMap<String,String>(); }
245 private final String readFileString( File file )
249 FileInputStream in = new FileInputStream( file );
250 BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ));
251 return reader.readLine();
253 catch( IOException e ) { return null; }
256 private final void copyAssetFile( String src )
258 File dest = new File( getFilesDir(), src );
261 Log.i( LOGTAG, "extracting " + dest );
262 dest.getParentFile().mkdirs();
263 dest.delete();
264 if (dest.createNewFile())
266 InputStream in = getAssets().open( src );
267 FileOutputStream out = new FileOutputStream( dest );
268 int read;
269 byte[] buffer = new byte[65536];
271 while ((read = in.read( buffer )) > 0) out.write( buffer, 0, read );
272 out.close();
273 if (isFileExecutable( src )) dest.setExecutable( true, true );
275 else
276 Log.i( LOGTAG, "Failed to create file " + dest );
278 catch( IOException e )
280 Log.i( LOGTAG, "Failed to copy asset file to " + dest );
281 dest.delete();
285 private final void deleteAssetFile( String src )
287 File dest = new File( getFilesDir(), src );
288 Log.i( LOGTAG, "deleting " + dest );
289 dest.delete();
292 private final void copyAssetFiles()
294 String new_sum = readMapFromAssetFile( "sums.sum" ).get( "files.sum" );
295 if (new_sum == null) return; // no assets
297 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( this );
298 String old_sum = prefs.getString( "files.sum", "" );
299 if (old_sum.equals( new_sum )) return; // no change
300 prefs.edit().putString( "files.sum", new_sum ).apply();
302 HashMap<String,String> existing_files = readMapFromDiskFile( "files.sum" );
303 HashMap<String,String> new_files = readMapFromAssetFile( "files.sum" );
304 ArrayList<String> copy_files = new ArrayList<String>();
305 copy_files.add( "files.sum" );
307 for (Map.Entry<String, String> entry : new_files.entrySet())
309 String name = entry.getKey();
310 if (!entry.getValue().equals( existing_files.remove( name ))) copy_files.add( name );
313 createProgressDialog( copy_files.size(), "Extracting files..." );
315 for (String name : existing_files.keySet()) deleteAssetFile( name );
317 for (String name : copy_files)
319 copyAssetFile( name );
320 runOnUiThread( new Runnable() { public void run() {
321 progress_dialog.incrementProgressBy( 1 ); }});
326 // Generic Wine window class
329 private HashMap<Integer,WineWindow> win_map = new HashMap<Integer,WineWindow>();
331 protected class WineWindow
333 static protected final int HWND_MESSAGE = 0xfffffffd;
334 static protected final int SWP_NOZORDER = 0x04;
335 static protected final int WS_VISIBLE = 0x10000000;
337 protected int hwnd;
338 protected int owner;
339 protected int style;
340 protected float scale;
341 protected boolean visible;
342 protected Rect visible_rect;
343 protected Rect client_rect;
344 protected WineWindow parent;
345 protected ArrayList<WineWindow> children;
346 protected Surface window_surface;
347 protected Surface client_surface;
348 protected SurfaceTexture window_surftex;
349 protected SurfaceTexture client_surftex;
350 protected WineWindowGroup window_group;
351 protected WineWindowGroup client_group;
353 public WineWindow( int w, WineWindow parent, float scale )
355 Log.i( LOGTAG, String.format( "create hwnd %08x", w ));
356 hwnd = w;
357 owner = 0;
358 style = 0;
359 visible = false;
360 visible_rect = client_rect = new Rect( 0, 0, 0, 0 );
361 this.parent = parent;
362 this.scale = scale;
363 children = new ArrayList<WineWindow>();
364 win_map.put( w, this );
365 if (parent != null) parent.children.add( this );
368 public void destroy()
370 Log.i( LOGTAG, String.format( "destroy hwnd %08x", hwnd ));
371 visible = false;
372 win_map.remove( this );
373 if (parent != null) parent.children.remove( this );
374 destroy_window_groups();
377 public WineWindowGroup create_window_groups()
379 if (client_group != null) return client_group;
380 window_group = new WineWindowGroup( this );
381 client_group = new WineWindowGroup( this );
382 window_group.addView( client_group );
383 client_group.set_layout( client_rect.left - visible_rect.left,
384 client_rect.top - visible_rect.top,
385 client_rect.right - visible_rect.left,
386 client_rect.bottom - visible_rect.top );
387 if (parent != null)
389 parent.create_window_groups();
390 if (visible) add_view_to_parent();
391 window_group.set_layout( visible_rect.left, visible_rect.top,
392 visible_rect.right, visible_rect.bottom );
394 return client_group;
397 public void destroy_window_groups()
399 if (window_group != null)
401 if (parent != null && parent.client_group != null) remove_view_from_parent();
402 window_group.destroy_view();
404 if (client_group != null) client_group.destroy_view();
405 window_group = null;
406 client_group = null;
409 public View create_whole_view()
411 if (window_group == null) create_window_groups();
412 window_group.create_view( false ).layout( 0, 0,
413 Math.round( (visible_rect.right - visible_rect.left) * scale ),
414 Math.round( (visible_rect.bottom - visible_rect.top) * scale ));
415 window_group.set_scale( scale );
416 return window_group;
419 public void create_client_view()
421 if (client_group == null) create_window_groups();
422 Log.i( LOGTAG, String.format( "creating client view %08x %s", hwnd, client_rect ));
423 client_group.create_view( true ).layout( 0, 0, client_rect.right - client_rect.left,
424 client_rect.bottom - client_rect.top );
427 protected void add_view_to_parent()
429 int pos = parent.client_group.getChildCount() - 1;
431 // the content view is always last
432 if (pos >= 0 && parent.client_group.getChildAt( pos ) == parent.client_group.get_content_view()) pos--;
434 for (int i = 0; i < parent.children.size() && pos >= 0; i++)
436 WineWindow child = parent.children.get( i );
437 if (child == this) break;
438 if (!child.visible) continue;
439 if (child == ((WineWindowGroup)parent.client_group.getChildAt( pos )).get_window()) pos--;
441 parent.client_group.addView( window_group, pos + 1 );
444 protected void remove_view_from_parent()
446 parent.client_group.removeView( window_group );
449 protected void set_zorder( WineWindow prev )
451 int pos = -1;
453 parent.children.remove( this );
454 if (prev != null) pos = parent.children.indexOf( prev );
455 parent.children.add( pos + 1, this );
458 protected void sync_views_zorder()
460 int i, j;
462 for (i = parent.children.size() - 1, j = 0; i >= 0; i--)
464 WineWindow child = parent.children.get( i );
465 if (!child.visible) continue;
466 View child_view = parent.client_group.getChildAt( j );
467 if (child_view == parent.client_group.get_content_view()) continue;
468 if (child != ((WineWindowGroup)child_view).get_window()) break;
469 j++;
471 while (i >= 0)
473 WineWindow child = parent.children.get( i-- );
474 if (child.visible) child.window_group.bringToFront();
478 public void pos_changed( int flags, int insert_after, int owner, int style,
479 Rect window_rect, Rect client_rect, Rect visible_rect )
481 boolean was_visible = visible;
482 this.visible_rect = visible_rect;
483 this.client_rect = client_rect;
484 this.style = style;
485 this.owner = owner;
486 visible = (style & WS_VISIBLE) != 0;
488 Log.i( LOGTAG, String.format( "pos changed hwnd %08x after %08x owner %08x style %08x win %s client %s visible %s flags %08x",
489 hwnd, insert_after, owner, style, window_rect, client_rect, visible_rect, flags ));
491 if ((flags & SWP_NOZORDER) == 0 && parent != null) set_zorder( get_window( insert_after ));
493 if (window_group != null)
495 window_group.set_layout( visible_rect.left, visible_rect.top,
496 visible_rect.right, visible_rect.bottom );
497 if (parent != null)
499 if (!was_visible && (style & WS_VISIBLE) != 0) add_view_to_parent();
500 else if (was_visible && (style & WS_VISIBLE) == 0) remove_view_from_parent();
501 else if (visible && (flags & SWP_NOZORDER) == 0) sync_views_zorder();
505 if (client_group != null)
506 client_group.set_layout( client_rect.left - visible_rect.left,
507 client_rect.top - visible_rect.top,
508 client_rect.right - visible_rect.left,
509 client_rect.bottom - visible_rect.top );
512 public void set_parent( WineWindow new_parent, float scale )
514 Log.i( LOGTAG, String.format( "set parent hwnd %08x parent %08x -> %08x",
515 hwnd, parent.hwnd, new_parent.hwnd ));
516 this.scale = scale;
517 if (window_group != null)
519 if (visible) remove_view_from_parent();
520 new_parent.create_window_groups();
521 window_group.set_layout( visible_rect.left, visible_rect.top,
522 visible_rect.right, visible_rect.bottom );
524 parent.children.remove( this );
525 parent = new_parent;
526 parent.children.add( this );
527 if (visible && window_group != null) add_view_to_parent();
530 public int get_hwnd()
532 return hwnd;
535 private void update_surface( boolean is_client )
537 if (is_client)
539 Log.i( LOGTAG, String.format( "set client surface hwnd %08x %s", hwnd, client_surface ));
540 if (client_surface != null) wine_surface_changed( hwnd, client_surface, true );
542 else
544 Log.i( LOGTAG, String.format( "set window surface hwnd %08x %s", hwnd, window_surface ));
545 if (window_surface != null) wine_surface_changed( hwnd, window_surface, false );
549 public void set_surface( SurfaceTexture surftex, boolean is_client )
551 if (is_client)
553 if (surftex == null) client_surface = null;
554 else if (surftex != client_surftex)
556 client_surftex = surftex;
557 client_surface = new Surface( surftex );
560 else
562 if (surftex == null) window_surface = null;
563 else if (surftex != window_surftex)
565 window_surftex = surftex;
566 window_surface = new Surface( surftex );
569 update_surface( is_client );
572 public void get_event_pos( MotionEvent event, int[] pos )
574 pos[0] = Math.round( event.getX() * scale + window_group.getLeft() );
575 pos[1] = Math.round( event.getY() * scale + window_group.getTop() );
580 // Window group for a Wine window, optionally containing a content view
583 protected class WineWindowGroup extends ViewGroup
585 private WineView content_view;
586 private WineWindow win;
588 WineWindowGroup( WineWindow win )
590 super( WineActivity.this );
591 this.win = win;
592 setVisibility( View.VISIBLE );
595 /* wrapper for layout() making sure that the view is not empty */
596 public void set_layout( int left, int top, int right, int bottom )
598 left *= win.scale;
599 top *= win.scale;
600 right *= win.scale;
601 bottom *= win.scale;
602 if (right <= left + 1) right = left + 2;
603 if (bottom <= top + 1) bottom = top + 2;
604 layout( left, top, right, bottom );
607 @Override
608 protected void onLayout( boolean changed, int left, int top, int right, int bottom )
610 if (content_view != null) content_view.layout( 0, 0, right - left, bottom - top );
613 public void set_scale( float scale )
615 if (content_view == null) return;
616 content_view.setPivotX( 0 );
617 content_view.setPivotY( 0 );
618 content_view.setScaleX( scale );
619 content_view.setScaleY( scale );
622 public WineView create_view( boolean is_client )
624 if (content_view != null) return content_view;
625 content_view = new WineView( WineActivity.this, win, is_client );
626 addView( content_view );
627 if (!is_client)
629 content_view.setFocusable( true );
630 content_view.setFocusableInTouchMode( true );
632 return content_view;
635 public void destroy_view()
637 if (content_view == null) return;
638 removeView( content_view );
639 content_view = null;
642 public WineView get_content_view()
644 return content_view;
647 public WineWindow get_window()
649 return win;
653 // View used for all Wine windows, backed by a TextureView
655 protected class WineView extends TextureView implements TextureView.SurfaceTextureListener
657 private WineWindow window;
658 private boolean is_client;
660 public WineView( Context c, WineWindow win, boolean client )
662 super( c );
663 window = win;
664 is_client = client;
665 setSurfaceTextureListener( this );
666 setVisibility( VISIBLE );
667 setOpaque( false );
668 setFocusable( true );
669 setFocusableInTouchMode( true );
672 public WineWindow get_window()
674 return window;
677 @Override
678 public void onSurfaceTextureAvailable( SurfaceTexture surftex, int width, int height )
680 Log.i( LOGTAG, String.format( "onSurfaceTextureAvailable win %08x %dx%d %s",
681 window.hwnd, width, height, is_client ? "client" : "whole" ));
682 window.set_surface( surftex, is_client );
685 @Override
686 public void onSurfaceTextureSizeChanged( SurfaceTexture surftex, int width, int height )
688 Log.i( LOGTAG, String.format( "onSurfaceTextureSizeChanged win %08x %dx%d %s",
689 window.hwnd, width, height, is_client ? "client" : "whole" ));
690 window.set_surface( surftex, is_client);
693 @Override
694 public boolean onSurfaceTextureDestroyed( SurfaceTexture surftex )
696 Log.i( LOGTAG, String.format( "onSurfaceTextureDestroyed win %08x %s",
697 window.hwnd, is_client ? "client" : "whole" ));
698 window.set_surface( null, is_client );
699 return false; // hold on to the texture since the app may still be using it
702 @Override
703 public void onSurfaceTextureUpdated(SurfaceTexture surftex)
707 @TargetApi(24)
708 public PointerIcon onResolvePointerIcon( MotionEvent event, int index )
710 return current_cursor;
713 @Override
714 public boolean onGenericMotionEvent( MotionEvent event )
716 if (is_client) return false; // let the whole window handle it
717 if (window.parent != null && window.parent != desktop_window) return false; // let the parent handle it
719 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
721 int[] pos = new int[2];
722 window.get_event_pos( event, pos );
723 Log.i( LOGTAG, String.format( "view motion event win %08x action %d pos %d,%d buttons %04x view %d,%d",
724 window.hwnd, event.getAction(), pos[0], pos[1],
725 event.getButtonState(), getLeft(), getTop() ));
726 return wine_motion_event( window.hwnd, event.getAction(), pos[0], pos[1],
727 event.getButtonState(), (int)event.getAxisValue(MotionEvent.AXIS_VSCROLL) );
729 return super.onGenericMotionEvent(event);
732 @Override
733 public boolean onTouchEvent( MotionEvent event )
735 if (is_client) return false; // let the whole window handle it
736 if (window.parent != null && window.parent != desktop_window) return false; // let the parent handle it
738 int[] pos = new int[2];
739 window.get_event_pos( event, pos );
740 Log.i( LOGTAG, String.format( "view touch event win %08x action %d pos %d,%d buttons %04x view %d,%d",
741 window.hwnd, event.getAction(), pos[0], pos[1],
742 event.getButtonState(), getLeft(), getTop() ));
743 return wine_motion_event( window.hwnd, event.getAction(), pos[0], pos[1],
744 event.getButtonState(), 0 );
747 @Override
748 public boolean dispatchKeyEvent( KeyEvent event )
750 Log.i( LOGTAG, String.format( "view key event win %08x action %d keycode %d (%s)",
751 window.hwnd, event.getAction(), event.getKeyCode(),
752 KeyEvent.keyCodeToString( event.getKeyCode() )));;
753 boolean ret = wine_keyboard_event( window.hwnd, event.getAction(), event.getKeyCode(),
754 event.getMetaState() );
755 if (!ret) ret = super.dispatchKeyEvent(event);
756 return ret;
760 // The top-level desktop view group
762 protected class TopView extends ViewGroup
764 public TopView( Context context, int hwnd )
766 super( context );
767 desktop_window = new WineWindow( hwnd, null, 1.0f );
768 addView( desktop_window.create_whole_view() );
769 desktop_window.client_group.bringToFront();
771 message_window = new WineWindow( WineWindow.HWND_MESSAGE, null, 1.0f );
772 message_window.create_window_groups();
775 @Override
776 protected void onSizeChanged( int width, int height, int old_width, int old_height )
778 Log.i( LOGTAG, String.format( "desktop size %dx%d", width, height ));
779 wine_desktop_changed( width, height );
782 @Override
783 protected void onLayout( boolean changed, int left, int top, int right, int bottom )
785 // nothing to do
789 protected WineWindow get_window( int hwnd )
791 return win_map.get( hwnd );
794 // Entry points for the device driver
796 public void create_desktop_window( int hwnd )
798 Log.i( LOGTAG, String.format( "create desktop view %08x", hwnd ));
799 setContentView( new TopView( this, hwnd ));
800 progress_dialog.dismiss();
801 wine_config_changed( getResources().getConfiguration().densityDpi );
804 public void create_window( int hwnd, boolean opengl, int parent, float scale, int pid )
806 WineWindow win = get_window( hwnd );
807 if (win == null)
809 win = new WineWindow( hwnd, get_window( parent ), scale );
810 win.create_window_groups();
811 if (win.parent == desktop_window) win.create_whole_view();
813 if (opengl) win.create_client_view();
816 public void destroy_window( int hwnd )
818 WineWindow win = get_window( hwnd );
819 if (win != null) win.destroy();
822 public void set_window_parent( int hwnd, int parent, float scale, int pid )
824 WineWindow win = get_window( hwnd );
825 if (win == null) return;
826 win.set_parent( get_window( parent ), scale );
827 if (win.parent == desktop_window) win.create_whole_view();
830 @TargetApi(24)
831 public void set_cursor( int id, int width, int height, int hotspotx, int hotspoty, int bits[] )
833 Log.i( LOGTAG, String.format( "set_cursor id %d size %dx%d hotspot %dx%d", id, width, height, hotspotx, hotspoty ));
834 if (bits != null)
836 Bitmap bitmap = Bitmap.createBitmap( bits, width, height, Bitmap.Config.ARGB_8888 );
837 current_cursor = PointerIcon.create( bitmap, hotspotx, hotspoty );
839 else current_cursor = PointerIcon.getSystemIcon( this, id );
842 public void window_pos_changed( int hwnd, int flags, int insert_after, int owner, int style,
843 Rect window_rect, Rect client_rect, Rect visible_rect )
845 WineWindow win = get_window( hwnd );
846 if (win != null)
847 win.pos_changed( flags, insert_after, owner, style, window_rect, client_rect, visible_rect );
850 public void createDesktopWindow( final int hwnd )
852 runOnUiThread( new Runnable() { public void run() { create_desktop_window( hwnd ); }} );
855 public void createWindow( final int hwnd, final boolean opengl, final int parent, final float scale, final int pid )
857 runOnUiThread( new Runnable() { public void run() { create_window( hwnd, opengl, parent, scale, pid ); }} );
860 public void destroyWindow( final int hwnd )
862 runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd ); }} );
865 public void setParent( final int hwnd, final int parent, final float scale, final int pid )
867 runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent, scale, pid ); }} );
870 public void setCursor( final int id, final int width, final int height,
871 final int hotspotx, final int hotspoty, final int bits[] )
873 if (Build.VERSION.SDK_INT < 24) return;
874 runOnUiThread( new Runnable() { public void run() { set_cursor( id, width, height, hotspotx, hotspoty, bits ); }} );
877 public void windowPosChanged( final int hwnd, final int flags, final int insert_after,
878 final int owner, final int style,
879 final int window_left, final int window_top,
880 final int window_right, final int window_bottom,
881 final int client_left, final int client_top,
882 final int client_right, final int client_bottom,
883 final int visible_left, final int visible_top,
884 final int visible_right, final int visible_bottom )
886 final Rect window_rect = new Rect( window_left, window_top, window_right, window_bottom );
887 final Rect client_rect = new Rect( client_left, client_top, client_right, client_bottom );
888 final Rect visible_rect = new Rect( visible_left, visible_top, visible_right, visible_bottom );
889 runOnUiThread( new Runnable() {
890 public void run() { window_pos_changed( hwnd, flags, insert_after, owner, style,
891 window_rect, client_rect, visible_rect ); }} );