xref: /AOO41X/main/sfx2/source/appl/shutdowniconunx.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 
2 #ifdef ENABLE_QUICKSTART_APPLET
3 
4 #include <unotools/moduleoptions.hxx>
5 
6 #include <unotools/dynamicmenuoptions.hxx>
7 
8 #include <gtk/gtk.h>
9 #include <glib.h>
10 #include <eggtray/eggtrayicon.h>
11 #include <vos/mutex.hxx>
12 #include <vcl/bitmapex.hxx>
13 #include <vcl/bmpacc.hxx>
14 #include <sfx2/app.hxx>
15 #ifndef _SFX_APP_HRC
16 #include "app.hrc"
17 #endif
18 #ifndef __SHUTDOWNICON_HXX__
19 #define USE_APP_SHORTCUTS
20 #include "shutdownicon.hxx"
21 #endif
22 
23 // Cut/paste from vcl/inc/svids.hrc
24 #define SV_ICON_SMALL_START                 25000
25 
26 #define SV_ICON_ID_OFFICE                       1
27 #define SV_ICON_ID_TEXT                         2
28 #define SV_ICON_ID_SPREADSHEET                  4
29 #define SV_ICON_ID_DRAWING                      6
30 #define SV_ICON_ID_PRESENTATION                 8
31 #define SV_ICON_ID_DATABASE                    14
32 #define SV_ICON_ID_FORMULA                     15
33 #define SV_ICON_ID_TEMPLATE                    16
34 
35 using namespace ::rtl;
36 using namespace ::osl;
37 
38 static ResMgr *pVCLResMgr;
39 static EggTrayIcon *pTrayIcon;
40 static GtkWidget *pExitMenuItem = NULL;
41 static GtkWidget *pOpenMenuItem = NULL;
42 
43 static void open_url_cb( GtkWidget *, gpointer data )
44 {
45 	ShutdownIcon::OpenURL( *(OUString *)data,
46 						   OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
47 }
48 
49 static void open_file_cb( GtkWidget * )
50 {
51 	if ( !ShutdownIcon::bModalMode )
52 		ShutdownIcon::FileOpen();
53 }
54 
55 static void open_template_cb( GtkWidget * )
56 {
57 	if ( !ShutdownIcon::bModalMode )
58 		ShutdownIcon::FromTemplate();
59 }
60 
61 static void systray_disable_cb()
62 {
63 	ShutdownIcon::SetAutostart( false );
64 	ShutdownIcon::terminateDesktop();
65 }
66 
67 static void exit_quickstarter_cb( GtkWidget * )
68 {
69 	egg_tray_icon_cancel_message (pTrayIcon, 1 );
70 	ShutdownIcon::getInstance()->terminateDesktop();
71 	plugin_shutdown_sys_tray();
72 }
73 
74 static void menu_deactivate_cb( GtkWidget *pMenu )
75 {
76 	gtk_menu_popdown( GTK_MENU( pMenu ) );
77 }
78 
79 static GdkPixbuf * ResIdToPixbuf( sal_uInt16 nResId )
80 {
81 	ResId aResId( SV_ICON_SMALL_START + nResId, *pVCLResMgr );
82 	BitmapEx aIcon( aResId );
83 	Bitmap pInSalBitmap = aIcon.GetBitmap();
84 	AlphaMask pInSalAlpha = aIcon.GetAlpha();
85 
86 	BitmapReadAccess* pSalBitmap = pInSalBitmap.AcquireReadAccess();
87 	BitmapReadAccess* pSalAlpha = pInSalAlpha.AcquireReadAccess();
88 
89 	g_return_val_if_fail( pSalBitmap != NULL, NULL );
90 
91 	Size aSize( pSalBitmap->Width(), pSalBitmap->Height() );
92 	g_return_val_if_fail( Size( pSalAlpha->Width(), pSalAlpha->Height() ) == aSize, NULL );
93 
94 	int nX, nY;
95 	guchar *pPixbufData = ( guchar * )g_malloc( 4 * aSize.Width() * aSize.Height() );
96 	guchar *pDestData = pPixbufData;
97 
98 	for( nY = 0; nY < pSalBitmap->Height(); nY++ )
99 	{
100 		for( nX = 0; nX < pSalBitmap->Width(); nX++ )
101 		{
102 			BitmapColor aPix;
103 			aPix = pSalBitmap->GetPixel( nY, nX );
104 			pDestData[0] = aPix.GetRed();
105 			pDestData[1] = aPix.GetGreen();
106 			pDestData[2] = aPix.GetBlue();
107 			if (pSalAlpha)
108 			{
109 				aPix = pSalAlpha->GetPixel( nY, nX );
110 				pDestData[3] = 255 - aPix.GetIndex();
111 			}
112 			else
113 				pDestData[3] = 255;
114 			pDestData += 4;
115 		}
116 	}
117 
118 	pInSalBitmap.ReleaseAccess( pSalBitmap );
119 	if( pSalAlpha )
120 		pInSalAlpha.ReleaseAccess( pSalAlpha );
121 
122 	return gdk_pixbuf_new_from_data( pPixbufData,
123 		GDK_COLORSPACE_RGB, sal_True, 8,
124 		aSize.Width(), aSize.Height(),
125 		aSize.Width() * 4,
126 		(GdkPixbufDestroyNotify) g_free,
127 		NULL );
128 }
129 
130 extern "C" {
131 static void oustring_delete (gpointer  data,
132 							 GClosure * /* closure */)
133 {
134 	OUString *pURL = (OUString *) data;
135 	delete pURL;
136 }
137 }
138 
139 static void add_item( GtkMenuShell *pMenuShell, const char *pAsciiURL,
140 					  OUString *pOverrideLabel,
141 					  sal_uInt16 nResId, GCallback pFnCallback )
142 {
143 	OUString *pURL = new OUString (OStringToOUString( pAsciiURL,
144 													  RTL_TEXTENCODING_UTF8 ));
145 	OString aLabel;
146 	if (pOverrideLabel)
147 		aLabel = OUStringToOString (*pOverrideLabel, RTL_TEXTENCODING_UTF8);
148 	else
149 	{
150 		ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
151 		aLabel = OUStringToOString (pShutdownIcon->GetUrlDescription( *pURL ),
152 									RTL_TEXTENCODING_UTF8);
153 	}
154 
155 	GdkPixbuf *pPixbuf= ResIdToPixbuf( nResId );
156 	GtkWidget *pImage = gtk_image_new_from_pixbuf( pPixbuf );
157 	g_object_unref( G_OBJECT( pPixbuf ) );
158 
159 	GtkWidget *pMenuItem = gtk_image_menu_item_new_with_label( aLabel );
160 	gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage );
161 	g_signal_connect_data( pMenuItem, "activate", pFnCallback, pURL,
162 						   oustring_delete, GConnectFlags(0));
163 
164 	gtk_menu_shell_append( pMenuShell, pMenuItem );
165 }
166 
167 // Unbelievably nasty
168 using namespace ::com::sun::star::uno;
169 using namespace ::com::sun::star::task;
170 using namespace ::com::sun::star::lang;
171 using namespace ::com::sun::star::beans;
172 
173 static void add_ugly_db_item( GtkMenuShell *pMenuShell, const char *pAsciiURL,
174 							  sal_uInt16 nResId, GCallback pFnCallback )
175 {
176     SvtDynamicMenuOptions aOpt;
177 	Sequence < Sequence < PropertyValue > > aMenu = aOpt.GetMenu( E_NEWMENU );
178 	for ( sal_Int32 n=0; n<aMenu.getLength(); n++ )
179     {
180         ::rtl::OUString aURL;
181 		::rtl::OUString aDescription;
182 		Sequence < PropertyValue >& aEntry = aMenu[n];
183 		for ( sal_Int32 m=0; m<aEntry.getLength(); m++ )
184 		{
185             if ( aEntry[m].Name.equalsAsciiL( "URL", 3 ) )
186                 aEntry[m].Value >>= aURL;
187             if ( aEntry[m].Name.equalsAsciiL( "Title", 5 ) )
188                 aEntry[m].Value >>= aDescription;
189 		}
190 
191 		if ( aURL.equalsAscii( BASE_URL ) && aDescription.getLength() )
192 		{
193 			add_item (pMenuShell, pAsciiURL, &aDescription, nResId, pFnCallback);
194             break;
195 		}
196 	}
197 }
198 
199 static GtkWidget *
200 add_image_menu_item( GtkMenuShell *pMenuShell,
201 					 const gchar *stock_id,
202 					 rtl::OUString aLabel,
203 					 GCallback     activate_cb )
204 {
205 	OString aUtfLabel = rtl::OUStringToOString (aLabel, RTL_TEXTENCODING_UTF8 );
206 
207 	GtkWidget *pImage;
208 	pImage = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_MENU );
209 
210 	GtkWidget *pMenuItem;
211 	pMenuItem = gtk_image_menu_item_new_with_label( aUtfLabel );
212 	gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage );
213 
214 	gtk_menu_shell_append( pMenuShell, pMenuItem );
215 	g_signal_connect( pMenuItem, "activate", activate_cb, NULL);
216 
217 	return pMenuItem;
218 }
219 
220 static void populate_menu( GtkWidget *pMenu )
221 {
222 	ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
223 	GtkMenuShell *pMenuShell = GTK_MENU_SHELL( pMenu );
224 	SvtModuleOptions aModuleOptions;
225 
226 	if ( aModuleOptions.IsWriter() )
227 		add_item (pMenuShell, WRITER_URL, NULL,
228 				  SV_ICON_ID_TEXT, G_CALLBACK( open_url_cb ));
229 
230 	if ( aModuleOptions.IsCalc() )
231 		add_item (pMenuShell, CALC_URL, NULL,
232 				  SV_ICON_ID_SPREADSHEET, G_CALLBACK( open_url_cb ));
233 
234 	if ( aModuleOptions.IsImpress() )
235 		add_item (pMenuShell, IMPRESS_URL, NULL,
236 				  SV_ICON_ID_PRESENTATION, G_CALLBACK( open_url_cb ));
237 
238 	if ( aModuleOptions.IsDraw() )
239 		add_item (pMenuShell, DRAW_URL, NULL,
240 				  SV_ICON_ID_DRAWING, G_CALLBACK( open_url_cb ));
241 
242     if ( aModuleOptions.IsDataBase() )
243 		add_ugly_db_item (pMenuShell, BASE_URL,
244 						  SV_ICON_ID_DATABASE, G_CALLBACK( open_url_cb ));
245 
246 	if ( aModuleOptions.IsMath() )
247 		add_item (pMenuShell, MATH_URL, NULL,
248 				  SV_ICON_ID_FORMULA, G_CALLBACK( open_url_cb ));
249 
250 	OUString aULabel = pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE );
251 	add_item (pMenuShell, "dummy", &aULabel,
252 			  SV_ICON_ID_TEMPLATE, G_CALLBACK( open_template_cb ));
253 
254 	OString aLabel;
255 	GtkWidget *pMenuItem;
256 
257 	pMenuItem = gtk_separator_menu_item_new();
258 	gtk_menu_shell_append( pMenuShell, pMenuItem );
259 
260 	pOpenMenuItem = add_image_menu_item
261         (pMenuShell, GTK_STOCK_OPEN,
262 		 pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ),
263 		 G_CALLBACK( open_file_cb ));
264 
265 	pMenuItem = gtk_separator_menu_item_new();
266 	gtk_menu_shell_append( pMenuShell, pMenuItem );
267 
268 	(void) add_image_menu_item
269         ( pMenuShell, GTK_STOCK_CLOSE,
270 		  pShutdownIcon->GetResString( STR_QUICKSTART_PRELAUNCH_UNX ),
271 		  G_CALLBACK( systray_disable_cb ) );
272 
273 	pMenuItem = gtk_separator_menu_item_new();
274 	gtk_menu_shell_append( pMenuShell, pMenuItem );
275 
276 	pExitMenuItem = add_image_menu_item
277         ( pMenuShell, GTK_STOCK_QUIT,
278 		  pShutdownIcon->GetResString( STR_QUICKSTART_EXIT ),
279 		  G_CALLBACK( exit_quickstarter_cb ) );
280 
281 	gtk_widget_show_all( pMenu );
282 }
283 
284 static void refresh_menu( GtkWidget *pMenu )
285 {
286 	if (!pExitMenuItem)
287 		populate_menu( pMenu );
288 
289 	bool bModal = ShutdownIcon::bModalMode;
290 	gtk_widget_set_sensitive( pExitMenuItem, !bModal);
291 	gtk_widget_set_sensitive( pOpenMenuItem, !bModal);
292 }
293 
294 extern "C" {
295 static void
296 layout_menu( GtkMenu *menu,
297 			 gint *x, gint *y, gboolean *push_in,
298 			 gpointer )
299 {
300 	GtkRequisition req;
301 	GtkWidget *ebox = GTK_BIN( pTrayIcon )->child;
302 
303 	gtk_widget_size_request( GTK_WIDGET( menu ), &req );
304 	gdk_window_get_origin( ebox->window, x, y );
305 
306 	(*x) += ebox->allocation.x;
307 	(*y) += ebox->allocation.y;
308 
309 	if (*y >= gdk_screen_get_height (gtk_widget_get_screen (ebox)) / 2)
310 		(*y) -= req.height;
311 	else
312 		(*y) += ebox->allocation.height;
313 
314 	*push_in = sal_True;
315 }
316 }
317 
318 static gboolean display_menu_cb( GtkWidget *,
319 								 GdkEventButton *event, GtkWidget *pMenu )
320 {
321 	if (event->button == 2)
322 		return sal_False;
323 
324 #ifdef TEMPLATE_DIALOG_MORE_POLISHED
325 	if (event->button == 1 &&
326 		event->type == GDK_2BUTTON_PRESS)
327 	{
328 		open_template_cb( NULL );
329 		return sal_True;
330 	}
331 	if (event->button == 3)
332 	{
333 		... as below ...
334 #endif
335 
336 	refresh_menu( pMenu );
337 
338 	gtk_menu_popup( GTK_MENU( pMenu ), NULL, NULL,
339 					layout_menu, NULL, 0, event->time );
340 
341 	return sal_True;
342 }
343 
344 extern "C" {
345 	static gboolean
346 	show_at_idle( gpointer )
347 	{
348 		::vos::OGuard aGuard( Application::GetSolarMutex() );
349 		gtk_widget_show_all( GTK_WIDGET( pTrayIcon ) );
350 		return sal_False;
351 	}
352 }
353 
354 void SAL_DLLPUBLIC_EXPORT plugin_init_sys_tray()
355 {
356 	::vos::OGuard aGuard( Application::GetSolarMutex() );
357 
358 	if( !g_type_from_name( "GdkDisplay" ) )
359 		return;
360 
361 	OString aLabel;
362 	ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
363 
364 	aLabel = rtl::OUStringToOString (
365 			pShutdownIcon->GetResString( STR_QUICKSTART_TIP ),
366 			RTL_TEXTENCODING_UTF8 );
367 
368 	pTrayIcon = egg_tray_icon_new( aLabel );
369 
370 	GtkWidget *pParent = gtk_event_box_new();
371 	GtkTooltips *pTooltips = gtk_tooltips_new();
372 	gtk_tooltips_set_tip( GTK_TOOLTIPS( pTooltips ), pParent, aLabel, NULL );
373 
374 	GtkWidget *pIconImage = gtk_image_new();
375 	gtk_container_add( GTK_CONTAINER( pParent ), pIconImage );
376 
377 	pVCLResMgr = CREATEVERSIONRESMGR( vcl );
378 
379 	GdkPixbuf *pPixbuf = ResIdToPixbuf( SV_ICON_ID_OFFICE );
380 	gtk_image_set_from_pixbuf( GTK_IMAGE( pIconImage ), pPixbuf );
381 	g_object_unref( pPixbuf );
382 
383 	GtkWidget *pMenu = gtk_menu_new();
384 	g_signal_connect (pMenu, "deactivate",
385 					  G_CALLBACK (menu_deactivate_cb), NULL);
386 	g_signal_connect( pParent, "button_press_event",
387 					  G_CALLBACK( display_menu_cb ), pMenu );
388 	gtk_container_add( GTK_CONTAINER( pTrayIcon ), pParent );
389 
390 	// Show at idle to avoid artefacts at startup
391 	g_idle_add (show_at_idle, (gpointer) pTrayIcon);
392 
393 	// disable shutdown
394 	pShutdownIcon->SetVeto( true );
395 	pShutdownIcon->addTerminateListener();
396 }
397 
398 void SAL_DLLPUBLIC_EXPORT plugin_shutdown_sys_tray()
399 {
400 	::vos::OGuard aGuard( Application::GetSolarMutex() );
401 	if( !pTrayIcon )
402 		return;
403 	gtk_widget_destroy( GTK_WIDGET( pTrayIcon ) );
404 	pTrayIcon = NULL;
405 	pExitMenuItem = NULL;
406 	pOpenMenuItem = NULL;
407 }
408 
409 #endif // ENABLE_QUICKSTART_APPLET
410