Back to index

lightning-sunbird  0.9+nobinonly
nullplugin.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stephen Mak <smak@sun.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * nullplugin.c
00042  *
00043  * Implementation of the null plugins for Unix.
00044  *
00045  * dp <dp@netscape.com>
00046  * updated 5/1998 <pollmann@netscape.com>
00047  * updated 9/2000 <smak@sun.com>
00048  *
00049  */
00050 
00051 #include <stdio.h>
00052 #include <gtk/gtk.h>
00053 #include <gdk/gdkx.h>
00054 #include <gdk/gdkkeysyms.h>
00055 
00056 /* Xlib/Xt stuff */
00057 #ifdef MOZ_X11
00058 #include <X11/Xlib.h>
00059 #include <X11/Intrinsic.h>
00060 #include <X11/cursorfont.h>
00061 #endif
00062 
00063 #include "npapi.h"
00064 #include "nullplugin.h"
00065 #include "prprf.h"
00066 
00067 #define DIALOGID "dialog"
00068 
00069 /* Global data */
00070 static MimeTypeElement *head = NULL;
00071 
00072 /* destroy the dialog box */
00073 void
00074 destroyWidget(PluginInstance *This)
00075 {
00076     if (This && This->dialogBox)
00077     {
00078       gtk_widget_destroy (GTK_WIDGET(This->dialogBox));
00079     }
00080 }
00081 
00082 /* callback function for the OK button */
00083 static void 
00084 DialogOKClicked (GtkButton *button, gpointer data)
00085 {
00086     PluginInstance* This = (PluginInstance*) data;
00087     GtkWidget* dialogWindow = gtk_object_get_data(GTK_OBJECT(button), DIALOGID);
00088     char *url;
00089 
00090     gtk_object_remove_data(GTK_OBJECT(button), DIALOGID);
00091 
00092     if (This->pluginsFileUrl != NULL)
00093     {
00094         /* Get the JavaScript command string */
00095         static const char buf[] = 
00096           "javascript:netscape.softupdate.Trigger.StartSoftwareUpdate(\"%s\")";
00097 
00098         url = NPN_MemAlloc(strlen(This->pluginsFileUrl) + (sizeof(buf) - 2));
00099         if (url != NULL)
00100         {
00101             /* Insert the file URL into the JavaScript command */
00102             sprintf(url, buf, This->pluginsFileUrl);
00103             NPN_GetURL(This->instance, url, TARGET);
00104             NPN_MemFree(url);
00105         }
00106     }
00107     else
00108     {
00109         /* If necessary, get the default plug-ins page resource */
00110         char* address = This->pluginsPageUrl;
00111         if (address == NULL || *address == 0)
00112         {
00113             address = PLUGINSPAGE_URL;
00114         }
00115 
00116         url = NPN_MemAlloc(strlen(address) + 1 + strlen(This->type)+1);
00117         if (url != NULL)
00118         {
00119             NPN_PushPopupsEnabledState(This->instance, TRUE);
00120                 /* Append the MIME type to the URL */
00121             sprintf(url, "%s?%s", address, This->type);
00122             if (strcmp (This->type, JVM_MINETYPE) == 0) 
00123             {
00124                 NPN_GetURL(This->instance, JVM_SMARTUPDATE_URL , TARGET);
00125             }
00126             else 
00127             {
00128                 NPN_GetURL(This->instance, url, TARGET);
00129             }
00130             NPN_MemFree(url);
00131             NPN_PopPopupsEnabledState(This->instance);
00132         }
00133     }
00134     destroyWidget(This);
00135 }
00136 
00137 /* the call back function for cancel button */
00138 static void 
00139 DialogCancelClicked (GtkButton *button, gpointer data) 
00140 {
00141     destroyWidget((PluginInstance*) data);
00142 }
00143 
00144 /* function that closes the dialog if ESC is pressed */
00145 static gboolean
00146 DialogEscapePressed (GtkWidget *widget, GdkEventKey *event, gpointer data)
00147 {
00148     if (event->keyval == GDK_Escape)
00149     {
00150         gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
00151         gtk_object_destroy (GTK_OBJECT (widget));
00152         return TRUE;
00153     }
00154 
00155     return FALSE;
00156 }
00157 
00158 /* a handy procedure to add a widget and pack it as well */
00159 static GtkWidget *
00160 AddWidget (GtkWidget *widget, GtkWidget *packingbox)
00161 {
00162     gtk_box_pack_start(GTK_BOX(packingbox), widget, TRUE, TRUE, 2);
00163     return widget;
00164 }
00165 
00166 
00167 
00168 /* MIMETypeList maintenance routines */
00169 
00170 static gboolean
00171 isEqual(NPMIMEType t1, NPMIMEType t2)
00172 {
00173     return (t1 && t2) ? (strcmp(t1, t2) == 0) : FALSE; 
00174 }
00175 
00176 static MimeTypeElement * 
00177 isExist(MimeTypeElement **typelist, NPMIMEType type)
00178 {
00179     MimeTypeElement *ele;
00180 
00181     ele = *typelist;
00182     while (ele != NULL) {
00183         if (isEqual(ele->pinst->type, type))
00184             return ele;
00185         ele = ele->next;
00186     }
00187     return NULL;
00188 }
00189 
00190 NPMIMEType
00191 dupMimeType(NPMIMEType type)
00192 {
00193     NPMIMEType mimetype = NPN_MemAlloc(strlen(type)+1);
00194     if (mimetype)
00195         strcpy(mimetype, type);
00196     return(mimetype);
00197 }
00198 
00199 static gboolean 
00200 addToList(MimeTypeElement **typelist, PluginInstance *This)
00201 {
00202     if (This && This->type && !isExist(typelist, This->type))
00203     {
00204         MimeTypeElement *ele;
00205         if ((ele = (MimeTypeElement *) NPN_MemAlloc(sizeof(MimeTypeElement))))
00206         {
00207             ele->pinst = This;
00208             ele->next = *typelist;
00209             *typelist = ele;
00210             return(TRUE);
00211         }
00212     }
00213     return(FALSE);
00214 }
00215 
00216 static gboolean
00217 delFromList(MimeTypeElement **typelist, PluginInstance *This)
00218 {
00219     if (typelist && This)
00220     {
00221         MimeTypeElement *ele_prev;
00222         MimeTypeElement *ele = *typelist;
00223         while (ele)
00224         {
00225             if (isEqual(ele->pinst->type, This->type))
00226             {
00227                 if (*typelist == ele)
00228                 {
00229                     *typelist = ele->next;
00230                 } else {
00231                     ele_prev->next = ele->next;
00232                 }
00233                 NPN_MemFree(ele);
00234                 return(TRUE);
00235             }
00236             ele_prev = ele;
00237             ele = ele->next;
00238         }
00239     }
00240     return(FALSE);
00241 }
00242 
00243 static void
00244 onDestroyWidget(GtkWidget *w, gpointer data)
00245 {
00246     PluginInstance* This = (PluginInstance*) data;
00247     if (This && This->dialogBox && This->dialogBox == w)
00248     {
00249         This->dialogBox = 0;
00250         delFromList(&head, This);
00251     }
00252 }
00253 
00254 /* create and display the dialog box */
00255 void 
00256 makeWidget(PluginInstance *This)
00257 {
00258     GtkWidget *dialogWindow;
00259     GtkWidget *dialogMessage;
00260     GtkWidget *okButton;
00261     GtkWidget *cancelButton;
00262     char message[1024];
00263     MimeTypeElement *ele;
00264 
00265     if (!This) return;
00266 
00267     /* need to check whether we already pop up a dialog box for previous
00268        minetype in the same web page. It's require otherwise there will
00269        be 2 dialog boxes pop if there are 2 plugin in the same web page
00270     */
00271     if ((ele = isExist(&head, This->type)))
00272     {
00273         if (ele->pinst && ele->pinst->dialogBox)
00274         {
00275             GtkWidget *top_window = gtk_widget_get_toplevel(ele->pinst->dialogBox);
00276             if (top_window && GTK_WIDGET_VISIBLE(top_window))
00277             {   /* this will raise the toplevel window */
00278                 gdk_window_show(top_window->window);
00279             }
00280         }
00281         return;
00282     }
00283 
00284     dialogWindow = gtk_dialog_new();
00285     This->dialogBox = dialogWindow;
00286     This->exists = TRUE;
00287     This->dialogBox = dialogWindow;
00288     addToList(&head, This);
00289     gtk_window_set_title(GTK_WINDOW(dialogWindow), PLUGIN_NAME);
00290     gtk_window_set_position(GTK_WINDOW(dialogWindow), GTK_WIN_POS_CENTER);
00291     gtk_window_set_modal(GTK_WINDOW(dialogWindow), FALSE);
00292     gtk_container_set_border_width(GTK_CONTAINER(dialogWindow), 20);
00293     gtk_window_set_policy(GTK_WINDOW(dialogWindow), FALSE, FALSE, TRUE);
00294 
00295     PR_snprintf(message, sizeof(message) - 1, MESSAGE, This->type);
00296     dialogMessage = AddWidget(gtk_label_new (message), 
00297                    GTK_DIALOG(dialogWindow)->vbox);
00298 
00299     okButton= AddWidget(gtk_button_new_with_label (OK_BUTTON), 
00300                    GTK_DIALOG(dialogWindow)->action_area);
00301     gtk_object_set_data(GTK_OBJECT(okButton), DIALOGID, dialogWindow);
00302 
00303     GTK_WIDGET_SET_FLAGS (okButton, GTK_CAN_DEFAULT);
00304     gtk_widget_grab_default(okButton);
00305 
00306     cancelButton= AddWidget(gtk_button_new_with_label (CANCEL_BUTTON), 
00307                    GTK_DIALOG(dialogWindow)->action_area);
00308 
00309     gtk_signal_connect (GTK_OBJECT(okButton),  "clicked",
00310                         GTK_SIGNAL_FUNC(DialogOKClicked), This);
00311 
00312     gtk_signal_connect (GTK_OBJECT(cancelButton),  "clicked",
00313                         GTK_SIGNAL_FUNC(DialogCancelClicked), This);
00314 
00315     gtk_signal_connect(GTK_OBJECT(dialogWindow), "key_press_event",
00316                         GTK_SIGNAL_FUNC (DialogEscapePressed), NULL);
00317 
00318     /* hookup to when the dialog is destroyed */
00319     gtk_signal_connect(GTK_OBJECT(dialogWindow), "destroy",
00320                         GTK_SIGNAL_FUNC(onDestroyWidget), This);
00321 
00322     gtk_widget_show_all(dialogWindow);
00323 }
00324 
00325 /* XPM */
00326 static char * npnul320_xpm[] = {
00327 "32 32 6 1",
00328 "       c None",
00329 ".      c #808080",
00330 "+      c #F8F8F8",
00331 "@      c #C0C0C0",
00332 "#      c #000000",
00333 "$      c #00F8F8",
00334 "........................++++++++",
00335 ".++++++++++++++++++++++..+++++++",
00336 ".+++++++++++++++++++++@.@.++++++",
00337 ".++@@@@@@@@@@@@@@@@@@@@.+@.+++++",
00338 ".++@@@@@@@@@.....@@@@@@.++@.++++",
00339 ".++@@@@@@@@.+++++#@@@@@.+++@.+++",
00340 ".++@@@@@@@.++$$$$$#@@@@.++++@.++",
00341 ".++@@@@@@@.+$$$$$$#.@@@.+++++@.+",
00342 ".++@@@...@@.+$$$$#..###.#######+",
00343 ".++@@.+++$$++$$$$$##++$#......#+",
00344 ".++@@.+$$$++$$$$$$$+$$$#......#+",
00345 ".++@@.+$$$$$$$$$$$$$$$$#..@@++#+",
00346 ".++@@@$$$$$$$$$$$$$$$$#...@@++#+",
00347 ".++@@@$#$##.$$$$$$##$$#...@@++#+",
00348 ".++@@@@##...$$$$$#..##...@@@++#+",
00349 ".++@@@@@....+$$$$#.......@@@++#+",
00350 ".++@@@@@@...+$$$$#.@@@..@@@@++#+",
00351 ".++@@@@..@@.+$$$$#.@##@@@@@@++#+",
00352 ".++@@@.++$$++$$$$$##$$#@@@@@++#+",
00353 ".++@@@.+$$++$$$$$$$$$$#@@@@@++#+",
00354 ".++@@.++$$$$$$$$$$$$$$$#@@@@++#+",
00355 ".++@@.+$$$$$$$$$$$$$$$$#.@@@++#+",
00356 ".++@@.+$$##$$$$$$$##$$$#..@@++#+",
00357 ".++@@@###...$$$$$#.@###...@@++#+",
00358 ".++@@@@....$$$$$$$#.@.....@@++#+",
00359 ".++@@@@@...$$$$$$$#..@...@@@++#+",
00360 ".++@@@@@@@@#$$$$$#...@@@@@@@++#+",
00361 ".++@@@@@@@@@#####...@@@@@@@@++#+",
00362 ".++@@@@@@@@@@......@@@@@@@@@++#+",
00363 ".+++++++++++++....++++++++++++#+",
00364 ".+++++++++++++++++++++++++++++#+",
00365 "###############################+"};
00366 
00367 
00368 static GdkPixmap *nullPluginGdkPixmap = 0;
00369 
00370 static GdkWindow *getGdkWindow(PluginInstance *This)
00371 {
00372 #ifdef MOZ_X11
00373     GdkWindow *gdk_window;
00374     Window xwin = (Window) This->window;
00375     Widget xt_w = XtWindowToWidget(This->display, xwin);
00376 
00377     if (xt_w) {
00378       xt_w = XtParent(xt_w);
00379       if (xt_w) {
00380          xwin = XtWindow(xt_w);
00381          /* xwin = xt_w->core.window; */
00382       }
00383     }
00384     gdk_window = gdk_window_lookup(xwin);
00385     return gdk_window;
00386 #else
00387     return NULL;
00388 #endif
00389 }
00390 
00391 static void
00392 createPixmap(PluginInstance *This)
00393 {
00394     int err = 0;
00395 
00396     if (nullPluginGdkPixmap == 0)
00397     { 
00398        GtkStyle *style;
00399        GdkBitmap *mask;
00400        GdkWindow *gdk_window = getGdkWindow(This);
00401        if (gdk_window)
00402        {
00403            GtkWidget *widget;
00404 #ifndef MOZ_WIDGET_GTK2
00405            widget = (GtkWidget *)gdk_window->user_data;
00406 #else
00407            gpointer user_data = NULL;
00408            gdk_window_get_user_data( gdk_window, &user_data);
00409            widget = GTK_WIDGET(user_data);
00410 #endif
00411            style = gtk_widget_get_style(widget);
00412            nullPluginGdkPixmap = gdk_pixmap_create_from_xpm_d(gdk_window , &mask,
00413                                              &style->bg[GTK_STATE_NORMAL], npnul320_xpm);
00414 #ifdef MOZ_X11
00415           /* Pixmap is created on original X session but used by new session */
00416           XSync(GDK_DISPLAY(), False);
00417 #endif
00418        }
00419     }
00420 }
00421 
00422 static void
00423 drawPixmap(PluginInstance *This)
00424 {
00425     if (nullPluginGdkPixmap)
00426     {
00427         int pixmap_with, pixmap_height, dest_x, dest_y;
00428         gdk_window_get_size((GdkWindow *)nullPluginGdkPixmap, &pixmap_with, &pixmap_height);
00429         dest_x = This->width/2 - pixmap_with/2;
00430         dest_y = This->height/2 - pixmap_height/2;
00431         if (dest_x >= 0 && dest_y >= 0)
00432         {
00433 #ifdef MOZ_X11
00434             GC gc;
00435             gc = XCreateGC(This->display, This->window, 0, NULL);
00436             XCopyArea(This->display, GDK_WINDOW_XWINDOW(nullPluginGdkPixmap) , This->window, gc,
00437                 0, 0, pixmap_with, pixmap_height, dest_x, dest_y);
00438             XFreeGC(This->display, gc);
00439 #endif
00440         }
00441     }
00442 }
00443 
00444 static void
00445 setCursor (PluginInstance *This)
00446 {
00447 #ifdef MOZ_X11
00448     static Cursor nullPluginCursor = 0;
00449     if (!nullPluginCursor)
00450     {
00451         nullPluginCursor = XCreateFontCursor(This->display, XC_hand2);
00452     }
00453     if (nullPluginCursor)
00454     {
00455         XDefineCursor(This->display, This->window, nullPluginCursor);
00456     }
00457 #endif
00458 }
00459 
00460 #ifdef MOZ_X11
00461 static void
00462 xt_event_handler(Widget xt_w, PluginInstance *This, XEvent *xevent, Boolean *b)
00463 {
00464     switch (xevent->type)
00465     {
00466         case Expose:
00467             /* get rid of all other exposure events */
00468             while(XCheckTypedWindowEvent(This->display, This->window, Expose, xevent));
00469             drawPixmap(This);
00470             break;
00471         case ButtonRelease:
00472             if (xevent->xbutton.button == Button1)
00473             {
00474                 makeWidget(This);
00475             } 
00476             break;
00477         default:
00478             break;
00479     }
00480 }
00481 #endif
00482 
00483 static void
00484 addXtEventHandler(PluginInstance *This)
00485 {
00486 #ifdef MOZ_X11
00487      Display *dpy = (Display*) This->display;
00488      Window xwin = (Window) This->window;
00489      Widget xt_w = XtWindowToWidget(dpy, xwin);
00490      if (xt_w)
00491      {
00492          long event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask;
00493          XSelectInput(dpy, xwin, event_mask);
00494          XtAddEventHandler(xt_w, event_mask, False, (XtEventHandler)xt_event_handler, This);
00495      }
00496 #endif
00497 }
00498 
00499 
00500 void
00501 makePixmap(PluginInstance *This)
00502 {
00503     createPixmap(This);
00504     drawPixmap(This);
00505     setCursor(This);
00506     addXtEventHandler(This);
00507 }