xref: /trunk/main/sfx2/source/appl/shutdowniconunx.cxx (revision 2722ceddc26af33ca9ed6a22fc3c4dfb805171c3)
1 
2 #ifdef ENABLE_QUICKSTART_APPLET
3 
4 #include <unotools/moduleoptions.hxx>
5 #include <unotools/dynamicmenuoptions.hxx>
6 
7 #include <gtk/gtk.h>
8 #include <glib.h>
9 #include <vos/mutex.hxx>
10 #include <vcl/bitmapex.hxx>
11 #include <vcl/bmpacc.hxx>
12 #include <sfx2/app.hxx>
13 #ifndef _SFX_APP_HRC
14 #include "app.hrc"
15 #endif
16 #ifndef __SHUTDOWNICON_HXX__
17 #define USE_APP_SHORTCUTS
18 #include "shutdownicon.hxx"
19 #endif
20 
21 // Cut/paste from vcl/inc/svids.hrc
22 #define SV_ICON_LARGE_START                 24000
23 #define SV_ICON_SMALL_START                 25000
24 
25 #define SV_ICON_ID_OFFICE                       1
26 #define SV_ICON_ID_TEXT                         2
27 #define SV_ICON_ID_SPREADSHEET                  4
28 #define SV_ICON_ID_DRAWING                      6
29 #define SV_ICON_ID_PRESENTATION                 8
30 #define SV_ICON_ID_DATABASE                    14
31 #define SV_ICON_ID_FORMULA                     15
32 #define SV_ICON_ID_TEMPLATE                    16
33 
34 using namespace ::rtl;
35 using namespace ::osl;
36 
37 static ResMgr *pVCLResMgr;
38 static GtkStatusIcon *pTrayIcon;
39 static GtkWidget *pExitMenuItem = NULL;
40 static GtkWidget *pOpenMenuItem = NULL;
41 static GtkWidget *pDisableMenuItem = 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     ShutdownIcon::getInstance()->terminateDesktop();
70     plugin_shutdown_sys_tray();
71 }
72 
73 static void menu_deactivate_cb( GtkWidget *pMenu )
74 {
75     gtk_menu_popdown( GTK_MENU( pMenu ) );
76 }
77 
78 static GdkPixbuf * ResIdToPixbuf( sal_uInt16 nResId )
79 {
80     ResId aResId( nResId, *pVCLResMgr );
81     BitmapEx aIcon( aResId );
82     Bitmap pInSalBitmap = aIcon.GetBitmap();
83     AlphaMask pInSalAlpha = aIcon.GetAlpha();
84 
85     BitmapReadAccess* pSalBitmap = pInSalBitmap.AcquireReadAccess();
86     BitmapReadAccess* pSalAlpha = pInSalAlpha.AcquireReadAccess();
87 
88     g_return_val_if_fail( pSalBitmap != NULL, NULL );
89 
90     Size aSize( pSalBitmap->Width(), pSalBitmap->Height() );
91     g_return_val_if_fail( Size( pSalAlpha->Width(), pSalAlpha->Height() ) == aSize, NULL );
92 
93     int nX, nY;
94     guchar *pPixbufData = ( guchar * )g_malloc( 4 * aSize.Width() * aSize.Height() );
95     guchar *pDestData = pPixbufData;
96 
97     for( nY = 0; nY < pSalBitmap->Height(); nY++ )
98     {
99         for( nX = 0; nX < pSalBitmap->Width(); nX++ )
100         {
101             BitmapColor aPix;
102             aPix = pSalBitmap->GetPixel( nY, nX );
103             pDestData[0] = aPix.GetRed();
104             pDestData[1] = aPix.GetGreen();
105             pDestData[2] = aPix.GetBlue();
106             if (pSalAlpha)
107             {
108                 aPix = pSalAlpha->GetPixel( nY, nX );
109                 pDestData[3] = 255 - aPix.GetIndex();
110             }
111             else
112                 pDestData[3] = 255;
113             pDestData += 4;
114         }
115     }
116 
117     pInSalBitmap.ReleaseAccess( pSalBitmap );
118     if( pSalAlpha )
119         pInSalAlpha.ReleaseAccess( pSalAlpha );
120 
121     return gdk_pixbuf_new_from_data( pPixbufData,
122         GDK_COLORSPACE_RGB, sal_True, 8,
123         aSize.Width(), aSize.Height(),
124         aSize.Width() * 4,
125         (GdkPixbufDestroyNotify) g_free,
126         NULL );
127 }
128 
129 extern "C" {
130 static void oustring_delete (gpointer  data,
131                              GClosure * /* closure */)
132 {
133     OUString *pURL = (OUString *) data;
134     delete pURL;
135 }
136 }
137 
138 static void add_item( GtkMenuShell *pMenuShell, const char *pAsciiURL,
139                       OUString *pOverrideLabel,
140                       sal_uInt16 nResId, GCallback pFnCallback )
141 {
142     OUString *pURL = new OUString (OStringToOUString( pAsciiURL,
143                                                       RTL_TEXTENCODING_UTF8 ));
144     OString aLabel;
145     if (pOverrideLabel)
146         aLabel = OUStringToOString (*pOverrideLabel, RTL_TEXTENCODING_UTF8);
147     else
148     {
149         ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
150         aLabel = OUStringToOString (pShutdownIcon->GetUrlDescription( *pURL ),
151                                     RTL_TEXTENCODING_UTF8);
152     }
153 
154     GdkPixbuf *pPixbuf= ResIdToPixbuf( SV_ICON_SMALL_START + nResId );
155     GtkWidget *pImage = gtk_image_new_from_pixbuf( pPixbuf );
156     g_object_unref( G_OBJECT( pPixbuf ) );
157 
158     GtkWidget *pMenuItem = gtk_image_menu_item_new_with_label( aLabel );
159     gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage );
160     g_signal_connect_data( pMenuItem, "activate", pFnCallback, pURL,
161                            oustring_delete, GConnectFlags(0));
162 
163     gtk_menu_shell_append( pMenuShell, pMenuItem );
164 }
165 
166 // Unbelievably nasty
167 using namespace ::com::sun::star::uno;
168 using namespace ::com::sun::star::task;
169 using namespace ::com::sun::star::lang;
170 using namespace ::com::sun::star::beans;
171 
172 static void add_ugly_db_item( GtkMenuShell *pMenuShell, const char *pAsciiURL,
173                               sal_uInt16 nResId, GCallback pFnCallback )
174 {
175     SvtDynamicMenuOptions aOpt;
176     Sequence < Sequence < PropertyValue > > aMenu = aOpt.GetMenu( E_NEWMENU );
177     for ( sal_Int32 n=0; n<aMenu.getLength(); n++ )
178     {
179         ::rtl::OUString aURL;
180         ::rtl::OUString aDescription;
181         Sequence < PropertyValue >& aEntry = aMenu[n];
182         for ( sal_Int32 m=0; m<aEntry.getLength(); m++ )
183         {
184             if ( aEntry[m].Name.equalsAsciiL( "URL", 3 ) )
185                 aEntry[m].Value >>= aURL;
186             if ( aEntry[m].Name.equalsAsciiL( "Title", 5 ) )
187                 aEntry[m].Value >>= aDescription;
188         }
189 
190         if ( aURL.equalsAscii( BASE_URL ) && aDescription.getLength() )
191         {
192             add_item (pMenuShell, pAsciiURL, &aDescription, nResId, pFnCallback);
193             break;
194         }
195     }
196 }
197 
198 static GtkWidget *
199 add_image_menu_item( GtkMenuShell *pMenuShell,
200                      const gchar *stock_id,
201                      rtl::OUString aLabel,
202                      GCallback     activate_cb )
203 {
204     OString aUtfLabel = rtl::OUStringToOString (aLabel, RTL_TEXTENCODING_UTF8 );
205 
206     GtkWidget *pImage;
207     pImage = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_MENU );
208 
209     GtkWidget *pMenuItem;
210     pMenuItem = gtk_image_menu_item_new_with_label( aUtfLabel );
211     gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage );
212 
213     gtk_menu_shell_append( pMenuShell, pMenuItem );
214     g_signal_connect( pMenuItem, "activate", activate_cb, NULL);
215 
216     return pMenuItem;
217 }
218 
219 static void populate_menu( GtkWidget *pMenu )
220 {
221     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
222     GtkMenuShell *pMenuShell = GTK_MENU_SHELL( pMenu );
223     SvtModuleOptions aModuleOptions;
224 
225     if ( aModuleOptions.IsWriter() )
226         add_item (pMenuShell, WRITER_URL, NULL,
227                   SV_ICON_ID_TEXT, G_CALLBACK( open_url_cb ));
228 
229     if ( aModuleOptions.IsCalc() )
230         add_item (pMenuShell, CALC_URL, NULL,
231                   SV_ICON_ID_SPREADSHEET, G_CALLBACK( open_url_cb ));
232 
233     if ( aModuleOptions.IsImpress() )
234         add_item (pMenuShell, IMPRESS_URL, NULL,
235                   SV_ICON_ID_PRESENTATION, G_CALLBACK( open_url_cb ));
236 
237     if ( aModuleOptions.IsDraw() )
238         add_item (pMenuShell, DRAW_URL, NULL,
239                   SV_ICON_ID_DRAWING, G_CALLBACK( open_url_cb ));
240 
241     if ( aModuleOptions.IsDataBase() )
242         add_ugly_db_item (pMenuShell, BASE_URL,
243                           SV_ICON_ID_DATABASE, G_CALLBACK( open_url_cb ));
244 
245     if ( aModuleOptions.IsMath() )
246         add_item (pMenuShell, MATH_URL, NULL,
247                   SV_ICON_ID_FORMULA, G_CALLBACK( open_url_cb ));
248 
249     OUString aULabel = pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE );
250     add_item (pMenuShell, "dummy", &aULabel,
251               SV_ICON_ID_TEMPLATE, G_CALLBACK( open_template_cb ));
252 
253     OString aLabel;
254     GtkWidget *pMenuItem;
255 
256     pMenuItem = gtk_separator_menu_item_new();
257     gtk_menu_shell_append( pMenuShell, pMenuItem );
258 
259     pOpenMenuItem = add_image_menu_item
260         (pMenuShell, GTK_STOCK_OPEN,
261          pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ),
262          G_CALLBACK( open_file_cb ));
263 
264 
265     pMenuItem = gtk_separator_menu_item_new();
266     gtk_menu_shell_append( pMenuShell, pMenuItem );
267 
268     pDisableMenuItem = 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     gtk_widget_set_sensitive( pDisableMenuItem, !bModal);
293 }
294 
295 
296 static gboolean display_menu_cb( GtkWidget *,
297                                  GdkEventButton *event, GtkWidget *pMenu )
298 {
299     if (event->button == 2)
300         return sal_False;
301 
302     refresh_menu( pMenu );
303 
304     gtk_menu_popup( GTK_MENU( pMenu ), NULL, NULL,
305                     gtk_status_icon_position_menu,
306                     pTrayIcon, 0, event->time );
307 
308     return sal_True;
309 }
310 
311 void SAL_DLLPUBLIC_EXPORT plugin_init_sys_tray()
312 {
313     ::vos::OGuard aGuard( Application::GetSolarMutex() );
314 
315     if( !g_type_from_name( "GdkDisplay" ) )
316         return;
317 
318     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
319     if ( !pShutdownIcon )
320         return;
321 
322     pTrayIcon = gtk_status_icon_new();
323     pVCLResMgr = CREATEVERSIONRESMGR( vcl );
324 
325     if ( !pTrayIcon || !pVCLResMgr )
326         return;
327 
328     // disable shutdown
329     pShutdownIcon->SetVeto( true );
330     pShutdownIcon->addTerminateListener();
331 
332     OString aLabel;
333 
334     aLabel = rtl::OUStringToOString (
335             pShutdownIcon->GetResString( STR_QUICKSTART_TIP ),
336             RTL_TEXTENCODING_UTF8 );
337 
338     GdkPixbuf *pPixbuf = ResIdToPixbuf( SV_ICON_LARGE_START + SV_ICON_ID_OFFICE );
339     g_object_set( G_OBJECT( pTrayIcon ),
340                   "pixbuf", pPixbuf,
341                   "title", aLabel.getStr(),
342                   NULL );
343     g_object_unref( pPixbuf );
344 
345     gtk_status_icon_set_tooltip_text( pTrayIcon, aLabel.getStr() );
346 
347     GtkWidget *pMenu = gtk_menu_new();
348 
349     g_signal_connect( pTrayIcon, "button-press-event",
350                       G_CALLBACK( display_menu_cb ), pMenu );
351 
352     g_signal_connect( pMenu, "deactivate",
353                       G_CALLBACK (menu_deactivate_cb), NULL);
354 }
355 
356 void SAL_DLLPUBLIC_EXPORT plugin_shutdown_sys_tray()
357 {
358     ::vos::OGuard aGuard( Application::GetSolarMutex() );
359     if( !pTrayIcon )
360         return;
361     g_object_unref( pTrayIcon );
362     pTrayIcon = NULL;
363     pExitMenuItem = NULL;
364     pOpenMenuItem = NULL;
365     pDisableMenuItem = NULL;
366 }
367 
368 #endif // ENABLE_QUICKSTART_APPLET
369